नमस्ते! आज हम एक बहुत ही महत्वपूर्ण विषय पर विचार करेंगे जो हमारी वस्तुओं से संबंधित है। अतिशयोक्ति के बिना, हम कह सकते हैं कि आप इस विषय का उपयोग वास्तविक जीवन में प्रतिदिन करेंगे! हम जावा कंस्ट्रक्टर्स के बारे में बात कर रहे हैं। यह पहली बार हो सकता है जब आप इस शब्द को सुन रहे हों, लेकिन आप वास्तव में पहले से ही कंस्ट्रक्टर का उपयोग कर चुके हैं। आपको अभी इसका एहसास नहीं हुआ :) हम बाद में खुद को इसके लिए मना लेते हैं।
याद रखें कि पाठ की शुरुआत में हमने कहा था कि आप पहले से ही इसे महसूस किए बिना कंस्ट्रक्टर का उपयोग कर चुके हैं? हमारा मतलब वही था जो हमने कहा था। तथ्य यह है कि जावा में प्रत्येक वर्ग में डिफ़ॉल्ट कन्स्ट्रक्टर कहा जाता है। यह कोई तर्क नहीं लेता है, लेकिन हर बार जब आप किसी वर्ग का कोई ऑब्जेक्ट बनाते हैं तो इसे लागू किया जाता है।
(CarFactory.java:15) CarFactory.main(CarFactory.java:23) पर निकास कोड 1 के साथ प्रक्रिया समाप्त
बूम! कार्यक्रम किसी प्रकार की अतुलनीय त्रुटि के साथ समाप्त होता है। क्या आप कारण का अनुमान लगाने का प्रयास कर सकते हैं? समस्या उस तर्क में है जिसे हम कंस्ट्रक्टर में डालते हैं। अधिक विशेष रूप से, यह पंक्ति:
दुनिया में कंस्ट्रक्टर क्या हैं और उनकी आवश्यकता क्यों है?
आइए दो उदाहरणों पर विचार करें।
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 की चौड़ाई वाली एक कार (यानी कोई पहिए नहीं), एक लापता ट्रंक, एक अज्ञात सामग्री से बना एक केबिन, और सबसे बढ़कर, एक अपरिभाषित मालिक . आप केवल कल्पना कर सकते हैं कि जब कार्यक्रम चल रहा हो तो ऐसी गलती "बंद" कैसे हो सकती है! हमें किसी तरह ऐसी स्थितियों से बचने की जरूरत है। हमें अपने कार्यक्रम को प्रतिबंधित करने की आवश्यकता है: नई कार बनाते समयवस्तु, हम चाहते हैं कि मॉडल और अधिकतम गति जैसे क्षेत्र हमेशा निर्दिष्ट हों। अन्यथा, हम वस्तु के निर्माण को रोकना चाहते हैं। कंस्ट्रक्टर इस काम को आसानी से हैंडल कर लेते हैं। उन्हें एक कारण के लिए अपना नाम मिला। कंस्ट्रक्टर एक प्रकार का वर्ग "कंकाल" बनाता है जिसे प्रत्येक नई वस्तु से मेल खाना चाहिए। सुविधा के लिए, दो क्षेत्रों के साथ कार वर्ग के सरल संस्करण पर वापस चलते हैं । हमारी आवश्यकताओं को ध्यान में रखते हुए, Car क्लास का कंस्ट्रक्टर इस तरह दिखेगा:
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;
}
लगभग शब्दशः व्याख्या की जा सकती है: " इस कार के लिए मॉडल (जिसे हम अभी बना रहे हैं) निर्माता को दिया गया मॉडल तर्क है। इस कार के लिए मैक्सस्पेड (जिसे हम बना रहे हैं) मैक्सस्पेड तर्क पास किया गया है। निर्माता।" और बस यही होता है:
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](https://cdn.codegym.cc/images/article/66a3ff7c-563d-4f53-af6e-3a03f1cf8ace/512.jpeg)
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);
}
}
हमारे पास CarFactory वर्ग है जो कार कारखाने का वर्णन करता है। कंस्ट्रक्टर के अंदर, हम सभी क्षेत्रों को इनिशियलाइज़ करते हैं और कुछ तर्क शामिल करते हैं: हम कारखाने के बारे में कुछ जानकारी प्रदर्शित करते हैं। ऐसा लगता है कि इसमें कोई बुराई नहीं है। कार्यक्रम ठीक काम करता है। कंसोल आउटपुट: हमारी कार फैक्ट्री को फोर्ड कहा जाता है, इसकी स्थापना 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);
}
}
कंसोल आउटपुट: हमारी कार फैक्ट्री को थ्रेड "मेन" java.lang.ArithmeticException में Amigo Motors Exception कहा जाता है: / शून्य से इसकी स्थापना 0 साल पहले हुई थी, उस समय से, इसने CarFactory में 1000 कारों का उत्पादन किया है।
System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
यहां आप एक गणना कर रहे हैं और कारखाने की उम्र से उत्पादित कारों की संख्या को विभाजित कर रहे हैं। और चूंकि हमारा कारखाना नया है (अर्थात यह 0 वर्ष पुराना है), हम 0 से विभाजित करते हैं, जो हम गणित में नहीं कर सकते। नतीजतन, कार्यक्रम एक त्रुटि के साथ समाप्त होता है।
GO TO FULL VERSION