हाय! आज आपण एका अतिशय महत्त्वाच्या विषयावर विचार करू जो आपल्या वस्तूंशी संबंधित आहे. अतिशयोक्ती न करता, आम्ही असे म्हणू शकतो की आपण दररोज वास्तविक जीवनात हा विषय वापराल! आम्ही Java Constructors बद्दल बोलत आहोत. ही संज्ञा तुम्ही प्रथमच ऐकत असाल, परंतु तुम्ही प्रत्यक्षात आधीच कन्स्ट्रक्टर वापरले आहेत. तुम्हाला ते कळलेच नाही :) आम्ही स्वतःला हे नंतर पटवून देतो.

जगात कन्स्ट्रक्टर काय आहेत आणि त्यांची गरज का आहे?

दोन उदाहरणे पाहू या.

public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car bugatti = new Car();
       bugatti.model = "Bugatti Veyron";
       bugatti.maxSpeed = 378;

   }
}
आम्ही आमची कार तयार केली आणि तिचे मॉडेल आणि कमाल वेग सेट केला. परंतु कार ऑब्जेक्टमध्ये प्रत्यक्ष प्रकल्पात 2 फील्ड्स नसतील. उदाहरणार्थ, त्यात 16 फील्ड असू शकतात!

public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate to 100 km/h (in seconds)


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

   }

}
आम्ही एक नवीन कार ऑब्जेक्ट तयार केला आहे. एक समस्या आहे: आमच्याकडे 16 फील्ड आहेत, परंतु आम्ही फक्त 12 सुरू केले आहेत ! आता कोड पहा आणि आम्ही विसरलेले फील्ड शोधण्याचा प्रयत्न करा! इतके सोपे नाही, हं? या परिस्थितीत, प्रोग्रामर सहजपणे चूक करू शकतो आणि काही फील्ड सुरू करण्यात अयशस्वी होऊ शकतो. परिणामी, प्रोग्राम चुकीचे वागेल:

public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate to 100 km/h (in seconds)


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

       System.out.println("Model: Bugatti Veyron. Engine volume: " + bugatti.engineVolume + ". Trunk volume: " + bugatti.trunkVolume + ". Cabin material: " + bugatti.cabinMaterial +
       ". Wheel width: " + bugatti.wheels + ". Purchased in 2018 by Mr. " + bugatti.ownerLastName);

   }

}
कन्सोल आउटपुट: मॉडेल: बुगाटी वेरॉन. इंजिन व्हॉल्यूम: 6.3. ट्रंक व्हॉल्यूम: 0. केबिन सामग्री: शून्य. चाकाची रुंदी: 0. 2018 मध्ये श्री. नल द्वारे खरेदी केलेले तुमच्या खरेदीदाराने, ज्याने कारसाठी $2 दशलक्ष सोडून दिले, त्याला " मिस्टर नल " म्हणणे नक्कीच आवडणार नाही! परंतु गंभीरपणे, सर्वात महत्त्वाची गोष्ट अशी आहे की आमच्या प्रोग्रामने चुकीच्या पद्धतीने एक वस्तू तयार केली आहे: 0 चाकाची रुंदी असलेली कार (म्हणजेच चाके नाहीत), एक गहाळ ट्रंक, अज्ञात सामग्रीपासून बनविलेले केबिन आणि सर्वात महत्त्वाचे म्हणजे, एक अपरिभाषित मालक . प्रोग्राम चालू असताना अशी चूक कशी "बंद" होऊ शकते याची आपण कल्पना करू शकता! आपण अशा परिस्थितीत कसे तरी टाळले पाहिजे. आम्हाला आमचा प्रोग्राम प्रतिबंधित करणे आवश्यक आहे: नवीन कार तयार करतानाऑब्जेक्ट, आम्हाला फील्ड, जसे की मॉडेल आणि कमाल गती, नेहमी निर्दिष्ट करायची आहे. अन्यथा, आम्हाला ऑब्जेक्टची निर्मिती रोखायची आहे. कन्स्ट्रक्टर हे काम सहजतेने हाताळतात. त्यांना त्यांचे नाव एका कारणाने मिळाले. कन्स्ट्रक्टर एक प्रकारचा वर्ग "कंकाल" तयार करतो जो प्रत्येक नवीन ऑब्जेक्टशी जुळला पाहिजे. सोयीसाठी, दोन फील्डसह कार क्लासच्या सोप्या आवृत्तीकडे परत जाऊ या . आमच्या गरजा लक्षात घेऊन, कार क्लासचे कन्स्ट्रक्टर असे दिसेल:

public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}

// And creating an object now looks like this:

public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 378);
}
कन्स्ट्रक्टर कसे घोषित केले जाते ते लक्षात घ्या. हे नियमित पद्धतीसारखेच आहे, परंतु त्यात परतावा प्रकार नाही. शिवाय, कन्स्ट्रक्टर अपरकेस अक्षराने सुरू होणारे वर्ग नाव ( कार ) निर्दिष्ट करतो. याव्यतिरिक्त, कन्स्ट्रक्टर हा तुमच्यासाठी नवीन असलेल्या कीवर्डसह वापरला जातो: हे . हा कीवर्ड विशिष्ट ऑब्जेक्ट दर्शवण्यासाठी आहे. कन्स्ट्रक्टरमधील कोड

public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
जवळजवळ शब्दशः अर्थ लावला जाऊ शकतो: " या कारचे मॉडेल (आम्ही आता तयार करत आहोत) हे कन्स्ट्रक्टरला दिलेले मॉडेल वितर्क आहे. या कारसाठी (आम्ही तयार करत आहोत) maxSpeed ​​वितर्क आहे कन्स्ट्रक्टर." आणि तेच घडते:

public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car("Bugatti Veyron", 378);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
कन्सोल आउटपुट: बुगाटी वेरॉन 378 कन्स्ट्रक्टरने आवश्यक मूल्ये योग्यरित्या नियुक्त केली आहेत. तुमच्या लक्षात आले असेल की कन्स्ट्रक्टर हे सामान्य पद्धतीसारखेच असते! तर आहे. कन्स्ट्रक्टर खरोखर एक पद्धत आहे, परंतु विशिष्ट वैशिष्ट्यांसह :) पद्धतींप्रमाणेच, आम्ही आमच्या कन्स्ट्रक्टरला युक्तिवाद दिले. आणि एखाद्या मेथडला कॉल केल्याप्रमाणे, कन्स्ट्रक्टरला कॉल करणे तुम्ही ते निर्दिष्ट केल्याशिवाय कार्य करणार नाही:

public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car(); // Error!
   }
  
}
आपण पाहू शकता की आपण जे साध्य करण्याचा प्रयत्न करत होतो ते कन्स्ट्रक्टर पूर्ण करतो. आता आपण वेग किंवा मॉडेलशिवाय कार तयार करू शकत नाही! कन्स्ट्रक्टर आणि पद्धतींमधील समानता येथे संपत नाही. पद्धतींप्रमाणेच, कन्स्ट्रक्टर ओव्हरलोड केले जाऊ शकतात. अशी कल्पना करा की तुमच्या घरी 2 पाळीव मांजरी आहेत. तुम्हाला त्यापैकी एक मांजरीचे पिल्लू म्हणून मिळाले. पण दुसरा जो तुम्ही रस्त्यावरून घेतला होता तो आधीच मोठा झाला होता आणि तो किती जुना आहे हे तुम्हाला माहीत नाही. या प्रकरणात, आमचा प्रोग्राम दोन प्रकारच्या मांजरी तयार करू इच्छितो: ज्यांचे नाव आणि वय आहे (पहिल्या मांजरीसाठी), आणि फक्त नाव असलेल्या (दुसऱ्या मांजरीसाठी). यासाठी, आम्ही कन्स्ट्रक्टर ओव्हरलोड करू:

public class Cat {

   String name;
   int age;

   // For the first cat
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For the second cat
   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
"नाव" आणि "वय" पॅरामीटर्ससह मूळ कन्स्ट्रक्टर व्यतिरिक्त, आम्ही फक्त नाव पॅरामीटरसह आणखी एक जोडला. तंतोतंत त्याच प्रकारे आम्ही मागील धड्यांमध्ये पद्धती ओव्हरलोड केल्या आहेत. आता आपण दोन्ही प्रकारच्या मांजरी तयार करू शकतो :)
आम्हाला कन्स्ट्रक्टर्सची गरज का आहे?  - 2
लक्षात ठेवा की धड्याच्या सुरुवातीला आम्ही सांगितले होते की तुम्ही आधीच कन्स्ट्रक्टर वापरल्या आहेत हे लक्षात न घेता? आम्ही जे बोललो तेच आम्हाला अभिप्रेत होतं. वस्तुस्थिती अशी आहे की Java मधील प्रत्येक वर्गाला डीफॉल्ट कन्स्ट्रक्टर म्हणतात. हे कोणतेही युक्तिवाद घेत नाही, परंतु प्रत्येक वेळी जेव्हा तुम्ही कोणत्याही वर्गाची कोणतीही वस्तू तयार करता तेव्हा ते मागवले जाते.

public class Cat {

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
पहिल्या दृष्टीक्षेपात, ते अदृश्य आहे. आम्ही एक वस्तू तयार केली, मग काय? कन्स्ट्रक्टर इथे कुठे काही करत आहे? ते पाहण्यासाठी, कॅट क्लाससाठी स्पष्टपणे रिक्त कन्स्ट्रक्टर लिहूया . आम्ही त्याच्या आत काही वाक्यांश प्रदर्शित करू. जर वाक्प्रचार प्रदर्शित केला असेल, तर कन्स्ट्रक्टरला बोलावले होते.

public class Cat {

   public Cat() {
       System.out.println("A cat has been created!");
   }

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
कन्सोल आउटपुट: एक मांजर तयार केली गेली आहे! पुष्टीकरण आहे! डीफॉल्ट कन्स्ट्रक्टर तुमच्या वर्गांमध्ये नेहमी अदृश्यपणे उपस्थित असतो. पण तुम्हाला त्याबद्दल आणखी एक गोष्ट माहित असणे आवश्यक आहे. एकदा तुम्ही आर्ग्युमेंटसह कन्स्ट्रक्टर तयार केल्यावर डिफॉल्ट कन्स्ट्रक्टर क्लासमधून काढून टाकला जातो. खरं तर, आम्ही वरील पुरावा आधीच पाहिले आहे. हे या कोडमध्ये होते:

public class Cat {

   String name;
   int age;

   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat smudge = new Cat(); //Error!
   }
}
आम्ही नाव आणि वय नसलेली मांजर तयार करू शकत नाही , कारण आम्ही स्ट्रिंग आणि इंट पॅरामीटर्ससह कॅट कन्स्ट्रक्टर घोषित केले आहे . यामुळे डीफॉल्ट कन्स्ट्रक्टर वर्गातून त्वरित गायब झाला. त्यामुळे लक्षात ठेवा की जर तुम्हाला तुमच्या वर्गात नो-आर्ग्युमेंट कन्स्ट्रक्टरसह अनेक कन्स्ट्रक्टर हवे असतील तर तुम्हाला ते स्वतंत्रपणे घोषित करावे लागेल. उदाहरणार्थ, समजा आम्ही पशुवैद्यकीय दवाखान्यासाठी एक कार्यक्रम तयार करत आहोत. आमच्या क्लिनिकला चांगली कामे करायची आहेत आणि ज्यांची नावे आणि वय माहित नाही अशा बेघर मांजरीच्या पिल्लांना मदत करायची आहे. मग आमचा कोड यासारखा दिसला पाहिजे:

public class Cat {

   String name;
   int age;

   // For cats with owners
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For street cats
   public Cat() {
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCat = new Cat();
   }
}
आता आम्ही स्पष्ट डिफॉल्ट कन्स्ट्रक्टर लिहिले आहे, आम्ही दोन्ही प्रकारच्या मांजरी तयार करू शकतो :) कोणत्याही पद्धतीप्रमाणे, कन्स्ट्रक्टरला दिलेला वितर्कांचा क्रम खूप महत्वाचा आहे. चला आमच्या कन्स्ट्रक्टरमध्ये नाव आणि वय वितर्क बदलू.

public class Cat {

   String name;
   int age;

   public Cat(int age, String name) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 10); // Error!
   }
}
चूक! कन्स्ट्रक्टर स्पष्टपणे नमूद करतो की जेव्हा एखादी मांजर वस्तू तयार केली जाते, तेव्हा त्याला या क्रमाने संख्या आणि स्ट्रिंग पास करणे आवश्यक आहे. त्यामुळे आमचा कोड काम करत नाही. हे लक्षात ठेवा आणि तुमचे स्वतःचे वर्ग घोषित करताना ते लक्षात ठेवा:

public Cat(String name, int age) {
   this.name = name;
   this.age = age;
}

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
हे दोन पूर्णपणे भिन्न कन्स्ट्रक्टर आहेत! जर आपण एका वाक्यात "मला कन्स्ट्रक्टरची गरज का आहे?" या प्रश्नाचे उत्तर व्यक्त करायचे असेल, तर आपण असे म्हणू शकतो, "वस्तूंची नेहमी वैध स्थिती आहे याची खात्री करण्यासाठी". तुम्ही कंस्ट्रक्टर वापरता तेव्हा तुमचे सर्व व्हेरिएबल्स योग्यरितीने सुरू केले जातील. तुमच्या प्रोग्राम्समध्ये 0 च्या स्पीड असलेल्या कोणत्याही कार किंवा इतर कोणतेही "अवैध" ऑब्जेक्ट नसतील. त्यांचा मुख्य फायदा प्रोग्रामरसाठी आहे. तुम्ही फील्ड मॅन्युअली सुरू केल्यास (ऑब्जेक्ट तयार केल्यानंतर), तुमच्याकडून काहीतरी चुकण्याचा आणि बगचा परिचय होण्याचा मोठा धोका असतो. परंतु हे कन्स्ट्रक्टरसह होणार नाही: जर तुम्ही सर्व आवश्यक वितर्क पास करण्यात अयशस्वी झालात किंवा तुम्ही चुकीच्या प्रकारचे वितर्क पास केले, तर कंपायलर त्वरित त्रुटी नोंदवेल. तुम्ही तुमचा कार्यक्रम ठेवू नका, असेही आम्ही वेगळे सांगायला हवे. कन्स्ट्रक्टरमधील तर्कशास्त्र. या पद्धती कशासाठी आहेत. पद्धती अशा आहेत जिथे तुम्ही सर्व आवश्यक कार्यक्षमता परिभाषित केली पाहिजे. कन्स्ट्रक्टरमध्ये तर्क जोडणे ही वाईट कल्पना का आहे ते पाहूया:

public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factory is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
आमच्याकडे कारफॅक्टरी वर्ग आहे जो कार कारखान्याचे वर्णन करतो. कन्स्ट्रक्टरच्या आत, आम्ही सर्व फील्ड सुरू करतो आणि काही तर्क समाविष्ट करतो: आम्ही कारखान्याबद्दल काही माहिती प्रदर्शित करतो. असे दिसते की यात काहीही वाईट नाही. कार्यक्रम छान चालतो. कन्सोल आउटपुट: आमच्या कार फॅक्टरीला फोर्ड म्हणतात. त्याची स्थापना 115 वर्षांपूर्वी झाली होती, तेव्हापासून, याने 50000000 कारचे उत्पादन केले आहे, सरासरी, ते प्रतिवर्षी 434782 कारचे उत्पादन करते परंतु आम्ही प्रत्यक्षात वेळ-उशीराची खाण टाकली आहे. आणि या प्रकारच्या कोडमुळे सहजपणे त्रुटी येऊ शकतात. समजा आता आपण फोर्ड बद्दल नाही तर "अमिगो मोटर्स" नावाच्या नवीन कारखान्याबद्दल बोलत आहोत, जो एका वर्षापेक्षा कमी काळ अस्तित्वात आहे आणि 1000 कार तयार करतो:

public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factor is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
कन्सोल आउटपुट: आमच्या कार फॅक्टरीला "मुख्य" थ्रेडमध्ये अमिगो मोटर्स अपवाद म्हटले जाते . अंकगणित अपवाद: / शून्याद्वारे याची स्थापना 0 वर्षांपूर्वी झाली होती, तेव्हापासून, कारफॅक्टरीमध्ये त्याने 1000 कारचे उत्पादन केले आहे. (CarFactory.java:15) CarFactory.main (CarFactory.java:23) येथे एक्झिट कोड 1 सह प्रक्रिया पूर्ण झाली बूम! कार्यक्रम काही प्रकारच्या न समजण्याजोग्या त्रुटीसह समाप्त होतो. आपण कारण अंदाज करण्याचा प्रयत्न करू शकता? समस्या आम्ही कन्स्ट्रक्टरमध्ये ठेवलेल्या तर्कामध्ये आहे. अधिक विशेषतः, ही ओळ:

System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
येथे तुम्ही गणना करत आहात आणि कारखान्याच्या वयानुसार उत्पादित कारची संख्या विभाजित करत आहात. आणि आमचा कारखाना नवीन असल्यामुळे (म्हणजे तो 0 वर्षांचा आहे), आम्ही 0 ने भागतो, जे आम्ही गणितात करू शकत नाही. परिणामी, प्रोग्राम त्रुटीसह समाप्त होतो.

आपण काय करायला हवे होते?

सर्व तर्क वेगळ्या पद्धतीत ठेवा. चला त्याला printFactoryInfo() म्हणू . तुम्ही तर्क म्हणून त्यावर CarFactory ऑब्जेक्ट पास करू शकता. तुम्ही तेथे सर्व तर्क लावू शकता आणि एकाच वेळी संभाव्य त्रुटी हाताळू शकता (जसे आमच्याकडे शून्य वर्षांचा समावेश आहे). प्रत्येकाला त्याचे स्वतःचे. वैध ऑब्जेक्ट स्थिती सेट करण्यासाठी कन्स्ट्रक्टर आवश्यक आहेत. आमच्याकडे व्यवसाय तर्कशास्त्राच्या पद्धती आहेत. एकाला दुसऱ्यात मिसळू नका. तुम्ही जे शिकलात ते बळकट करण्यासाठी, आम्ही तुम्हाला आमच्या Java कोर्समधील व्हिडिओ धडा पाहण्याची सूचना देतो