2014-11-09 7 views
12

बोलो एक उदाहरण है जो मैंने ट्यूटोरियल पॉइंट्स, एक निर्माता का उदाहरण दिया है। मुझे उनमें से अधिकतर मिला, लेकिन मुझे नहीं लगता कि आपको एक निर्माता और एक विधि क्यों चाहिए।रचनाकारों और विधियों के बीच अंतर

public Puppy(String name){ 
    System.out.println("Passed Name is :" + name); 
} 

मेरा प्रश्न है, इसके बजाय आपको ऐसा करने से क्या रोकता है?

public static void Puppy(String name){ 
    System.out.println("Passed Name is: "+name); 
} 

क्या ये दोनों एक ही बात नहीं करते हैं?

यहाँ संदर्भ के लिए पूरा कार्यक्रम है:

public class Puppy { 
    int puppyAge; 

    public Puppy(String name) { 
     System.out.println("Passed Name is :" + name); 
    } 

    public void setAge(int age) { 
     puppyAge = age; 
    } 

    public int getAge() { 
     System.out.println("Puppy's age is :" + puppyAge); 
     //what does this return do? since the puppyAge is already printed above. 
     return puppyAge; 
    } 

    public static void main(String []args){ 
     Puppy myPuppy = new Puppy("tommy"); 

     myPuppy.setAge(2); 
     myPuppy.getAge(); 

     System.out.println("Variable Value :" + myPuppy.puppyAge); 
    } 
} 
+0

आप किस विधि पर विश्वास करते हैं कि कन्स्ट्रक्टर के काम को डुप्लिकेट कर रहा है? केवल अगर कन्स्ट्रक्टर और दूसरी विधि एक ही कार्य कर रही है तो उनमें से एक अनावश्यक हो सकती है। इस मामले में, हालांकि, कन्स्ट्रक्टर उन सभी चीजों को नहीं कर रहा है जो इसे करना चाहिए - विशेष रूप से एक निर्माता को कक्षा में सभी सदस्य चर के मान निर्धारित करना चाहिए (और यह puppyAge को सेट नहीं कर रहा है, इसलिए उदाहरण एक अनिर्धारित है निर्माण के तुरंत बाद राज्य) और यह एक चर सेट करने के लिए पिल्ला के नाम का उपयोग नहीं कर रहा है (तो यह पिल्ला के नाम के साथ क्यों प्रदान किया जाता है?)। – Simon

उत्तर

5

निर्माता ये हैं तरीकों, वे तरीकों में से विशेष प्रकार के होते हैं तथापि,। रचनाकार ऐसे तरीके हैं जिनके पास रिटर्न प्रकार नहीं है और उन्हें अपने संलग्न वर्ग के नाम पर रखा जाना चाहिए। तो हमें रचनाकारों की आवश्यकता क्यों है? अच्छा, इस तरह हम कक्षाओं के उदाहरण बना सकते हैं। जब आप किसी निश्चित वर्ग का उदाहरण बनाना चाहते हैं, तो आप इसके कन्स्ट्रक्टर को कॉल करके ऐसा करते हैं। निर्माता वस्तु के लिए स्मृति को सुरक्षित रखता है और नव निर्मित वस्तु का संदर्भ देता है।

2

एक कन्स्ट्रक्टर ऑब्जेक्ट को स्थापित करने के लिए होना चाहिए जहां एक विधि वस्तु के साथ कुछ क्रिया करता है। जावा ऑब्जेक्ट उन्मुख है इसलिए पूरी भाषा ऑब्जेक्ट के चारों ओर घूमती है। कन्स्ट्रक्टर भी कुछ भी वापस नहीं कर सकते हैं और ऑब्जेक्ट के उदाहरण को वापस करने के लिए नए के साथ इस्तेमाल किया जाना चाहिए जहां विधियां कुछ भी लौट सकती हैं या कुछ भी नहीं।

2

Constructor ऐसा करता है कि यह उस वस्तु को "संरचना" बनाता है जिसे आप तकनीकी रूप से बना रहे हैं Method का एक विशिष्ट प्रकार है। Method ऑब्जेक्ट को संशोधित करने के लिए प्रयोग किया जाता है, अधिकांशतः तर्क का एक टुकड़ा करने के लिए। देखें: single responsibility principle

कक्षाएं/विधियां सरल होनी चाहिए और जानकारी के सटीक टुकड़ों को संभालना चाहिए उदाहरण के लिए Shape ऑब्जेक्ट लें, यदि आप चाहते थे कि यह गुण लंबाई, चौड़ाई, ऊंचाई, मात्रा, क्षेत्र, ect ... हो, तो आपके कन्स्ट्रक्टर को होना होगा :

public Shape (double length, double width, double height, double volume, double area, ect...) { 
    //code here 
} 

(इस विधि का नाम नोटिस वर्ग के नाम के रूप में एक ही होना चाहिए, वाचक एक 'Constructor`)

यह है कि क्या एक code smell के रूप में जानते है, विशेष रूप से: कई पैरामीटर । पढ़ना मुश्किल है, बहुत व्यवस्थित नहीं है और कोड लिखने का एक बुरा तरीका है। बजाय, तरीकों इन चरों स्थापित करने के लिए उपयोग किया जाता है:

public void setLength(double length) { 
    //code here 
} 

फिर अपने निर्माता केवल होगा:

public Shape() { 
    //code here 
} 

यह सिर्फ एक सरल उदाहरण है। कई मामलों में आप मामले के आधार पर कन्स्ट्रक्टर में पैरामीटर (या कुछ) पास करना चाह सकते हैं।

2

उस उदाहरण के लिए, आपको एक निर्माता की आवश्यकता नहीं है। यह एक बहुत बुरा उदाहरण है। एक विधि भी काम करेगा।

(यदि आप एक नहीं जोड़ते हैं, तो आप अभी भी new Puppy() फोन एक उदाहरण प्राप्त करने के लिए कर सकता है सभी जावा वर्गों एक डिफ़ॉल्ट निर्माता है।)

3

वहाँ निर्माणकर्ता और तरीकों के बीच एक बहुत बड़ा अंतर है।जब आप एक वस्तु का दृष्टांत है जैसे कि यह नई कीवर्ड के उपयोग से कार्यक्रम

Puppy myPuppy = new Puppy("tommy"); 

में किया है JVM निर्माता वस्तु बनाने के लिए कहता है। तो रचनाकार ऐसी वस्तुएं बनाते हैं जो मौजूद नहीं हैं लेकिन विधियां मौजूद वस्तुओं से जुड़ी हैं। आप इस लिंक http://www.javaworld.com/article/2076204/core-java/understanding-constructors.html

22

पर अधिक पढ़ सकते हैं आपको एक उदाहरण की मूल अवधारणा नहीं मिली, जो ओओपी में मौलिक है। यदि आप एक रूपक चाहते हैं, तो चलो कारों के बारे में बात करते हैं।

मुझे यकीन है कि आप जानते हैं कि एक कार क्या है; आप जानते हैं कि यह आपको एक स्थान से दूसरे स्थान पर जाने में सक्षम बनाता है, जिसमें 4 पहियों और अन्य हैं। यह एक अवधारणा है, और आपके गेराज में वास्तविक कार इस अवधारणा के उदाहरण < => कक्षा) है।

एक निर्माता का लक्ष्य एक उदाहरण बनाना है, कुछ पाठ मुद्रित नहीं करना है। एक कन्स्ट्रक्टर के बिना, आप कभी भी अपनी कक्षा की एक गैर स्थैतिक विधि को कॉल करने में सक्षम नहीं होंगे। आप एक कार की अवधारणा को ड्राइव करने में सक्षम नहीं होंगे, आपको पहले एक कार बनाने की आवश्यकता होगी।

बस उन विचारों की समीक्षा करें; आप इसके बिना कहीं नहीं मिलेगा।

3

पहले से ही रचनाकारों के बारे में कई अच्छे उत्तर।

एक मामूली बिंदु; आपके पास अपनी कक्षा के समान नाम के साथ एक स्थिर विधि नहीं हो सकती है। रचनाकारों के लिए यह नाम आरक्षित है।

2

जब आप किसी ऑब्जेक्ट का नया उदाहरण बनाते हैं (Puppy doggy = new Puppy("Bobby");) कन्स्ट्रक्टर को तुरंत कॉल किया जाता है। यह नई वस्तुओं का निर्माण करता है। यह इसे "बॉबी" नाम से बना देता है। (पिल्ला का नाम "बॉबी" नाम से हुआ है)। मान लीजिए कि हमारा पिल्ला इसके नाम से असंतुष्ट है और आप इसे "स्नूपी" में बदलना चाहते हैं। फिर आप विधि को कॉल करेंगे: doggy.setName("Snoopy");

10

मुझे लगता है कि यही कारण है कि निर्माता का उपयोग कर बनाई गई है अपने प्रश्न है ...

public Puppy(String name) 

... के बजाय ...

public static void Puppy(String name) 

..., है ना?

यदि यह है, तो सबसे पहले आपको यह करना चाहिए कि एक निर्माता विशेष विधि एक वर्ग के स्वामित्व में है जिसे आप उस कक्षा का नया उदाहरण बनाते हैं। तो अगर, उदाहरण के लिए, तो आप इस वर्ग है ...

public class Clazz { 
    public Clazz (String s) { 
     System.out.println(s); 
    } 
} 

..., तो जब भी आप इस वर्ग की तरह का एक नया उदाहरण बनाने ...

Clazz c = new Clazz("Hello World"); 

..., निर्माता को बुलाया जाएगा और वह विधि निष्पादित की जाएगी। (इस उदाहरण में, यह स्क्रीन पर "हैलो वर्ल्ड" प्रिंट करेगा।)

यह कहा गया है कि आप देख सकते हैं कि कन्स्ट्रक्टर एक विधि है, लेकिन यह एक विशेष विधि है जिसे कक्षा को तत्काल माना जाता है।तो, आपके प्रश्न के संबंध में, नियमित विधि शीर्षलेख की बजाय कन्स्ट्रक्टर सही तरीके से क्यों है, संकलक को इंगित करना है कि यह एक निर्माता और नियमित विधि नहीं है। यदि आप public Clazz() के बजाय public void Clazz() लिखते हैं, तो संकलक आपके कन्स्ट्रक्टर को पहचान नहीं पाएगा, और आपको लगता है कि यह केवल एक नियमित विधि है।

ध्यान दें कि निर्माता कभी भी कुछ भी वापस नहीं करते हैं, इसलिए शून्य कीवर्ड का उपयोग करना आवश्यक नहीं होगा। साथ ही, कन्स्ट्रक्टर स्थिर बनाने में कोई समझ नहीं है, क्योंकि कन्स्ट्रक्टर को तब कहा जाता है जब कोई नई ऑब्जेक्ट तत्काल हो जाती है।

+1

'निर्माता कभी भी कुछ भी वापस नहीं करते हैं, इसलिए शून्य कीवर्ड का उपयोग करना आवश्यक नहीं होगा' यह इसके बारे में सोचने का एक अजीब तरीका है। मैंने हमेशा विपरीत विचार किया है: वे अपने विशिष्ट प्रकार की वस्तु वापस कर देते हैं। 'सार्वजनिक क्लैज()' में 'मैं' क्लैज 'वापसी प्रकार पर विचार करूंगा, न कि "विधि" नाम। – nbrooks

+0

@nbrooks आपने जो कहा वह समझ में आता है। लेकिन जावा दस्तावेज़ों में यह लिखा गया है कि कन्स्ट्रक्टर ** ** ** रिटर्न प्रकार नहीं है। लेकिन अब आपने यह कहा है, मुझे लगता है कि दोनों तरीकों से सोच सही है – felipeek

+0

मुझे लगता है कि दस्तावेज़ कहते हैं कि आप 'वापसी' कीवर्ड का उपयोग नहीं करते हैं, न कि कोई वापसी प्रकार नहीं है। हम जानते हैं कि यह कुछ देता है, अन्यथा आप इस तरह की विधि कॉल के साथ चेन कन्स्ट्रक्टर नहीं कर सकते: 'नया स्ट्रिंग ("हैलो वर्ल्ड")। सबस्ट्रिंग (3) '। – nbrooks

2

एक कन्स्ट्रक्टर प्रकार विधि का है। विशेष रूप से इसे तब कहा जाता है जब आप उस वर्ग के किसी ऑब्जेक्ट को तुरंत चालू करते हैं। तो अपने उदाहरण में यदि आप लिखना:

Puppy pup = new Puppy("Rover"); 

आप एक वस्तु pup कहा जाता है और उस वस्तु है, जो आप इसका इस्तेमाल करने की अनुमति देता instantiating बनाते हैं। इसे तुरंत चालू करके, आप इस मामले में निर्दिष्ट कन्स्ट्रक्टर को कॉल करते हैं: public Puppy(String name) जो "Rover" पर प्रिंट सेट करता है, हालांकि यह वास्तव में एक कन्स्ट्रक्टर का अच्छा उपयोग नहीं है। String puppyName; को फ़ील्ड वैरिएबल के रूप में और अधिक समझदारी होगी, और this.puppyName = name को p.puppyName को कन्स्ट्रक्टर में जो भी पास किया गया है उसके बराबर सेट करने के लिए होगा।

5

Java Spec for Constructors में कहा:

  • कंस्ट्रक्टर्स कुछ भी वापस नहीं करते हैं, इस तरह वे कोई वापसी प्रकार है।

    अन्य सभी मामलों में, निर्माता घोषणा एक विधि घोषणा की तरह दिखती है जिसका कोई परिणाम नहीं है (§8.4.5)।

  • आप एक निर्माता को ओवरराइड नहीं कर सकते हैं।

    कन्स्ट्रक्टर घोषणाएं सदस्य नहीं हैं। वे कभी विरासत में नहीं होते हैं और इसलिए छिपाने या ओवरराइडिंग के अधीन नहीं होते हैं।

  • वे उदाहरण चर सीधे उपयोग नहीं कर सकते, बजाय वे कक्षाओं 'चर को सौंपने के लिए this और super उपयोग करना चाहिए।

    एक निर्माता शरीर में एक स्पष्ट निर्माता मंगलाचरण बयान किसी भी उदाहरण चर या उदाहरण के तरीकों या इनर क्लासों इस वर्ग या किसी सुपर क्लास में घोषित करने का उल्लेख नहीं हो सकता है, या किसी भी अभिव्यक्ति में इस या सुपर का उपयोग करें; अन्यथा, एक संकलन-समय त्रुटि होती है।

+0

मुझे लगता है कि आपने यह अंतिम गलत पढ़ा है: आप कन्स्ट्रक्टर में किसी भी वर्ग या इंस्टेंस चर का उपयोग कर सकते हैं, लेकिन 'सुपर (...)' या 'यह (...)' का आह्वान कर सकते हैं उदाहरण के सदस्यों या वर्ग के सदस्यों तक नहीं पहुंच सकते हैं। –

2

मैं वास्तव में नहीं बल्कि OOP की अवधारणाओं के बारे में और इस मामले जावा में एक किताब है, यहाँ सब (अच्छा) जवाब पढ़ने से पढ़ा होगा। आपको शायद बहुत सारे जवाब मिलेंगे, क्योंकि यह सवाल काफी लोकप्रिय है, लेकिन उत्तर सभी आवश्यक विवरणों में नहीं जाएंगे।

लेकिन एक बात मैं संक्षेप में उल्लेख करना चाहते हैं:

public int getAge() { 
    System.out.println("Puppy's age is :" + puppyAge); 
    //what does this return do? since the puppyAge is already printed above. 
    return puppyAge; 
} 

एक विधि जवाब किसी प्रकार के साथ लौट सकते हैं। तो यह विधि क्या करती है? यह वैरिएबल में सहेजा गया मान, puppyAge, नाम से वैरिएबल में सहेजा गया है जो एक पूर्णांक है। तो यदि आप विधि myPuppy.getAge() पर कॉल करते हैं, तो इस विधि में सबकुछ (वास्तव में प्रिंट आउट भी), संसाधित हो जाएगा और बाद में यह वापस आ जाएगा। आपके मामले में आप कहीं भी वापसी मूल्य को नहीं बचाते हैं। लेकिन 'सामान्य' चीज जो आप करना चाहते हैं, वह विधि के माध्यम से पिल्ला की उम्र तक पहुंचने के लिए होगी और वास्तव में इसके साथ कुछ करें, जैसे कि आपके सभी पिल्ले और सामान की औसत आयु की गणना करें। निश्चित रूप से, आप क्लास के बाहर से चर का उपयोग कर सकते हैं, क्योंकि आपने दृश्यता संशोधक सेट नहीं किया है, जैसे सार्वजनिक, निजी, संरक्षित।

public class Puppy { 
    int puppyAge; 

वास्तव में कोई सार्वजनिक संशोधक का अर्थ भी नहीं है, लेकिन यह अब के लिए प्रासंगिक नहीं है।

private int age; 

और getAge() की तरह एक विधि के माध्यम से उस तक पहुँच और इसके साथ कुछ करना चाहते:

int allAgesummed = puppy1.getAge() + puppy2.getAge() + 
puppy3.getAge(); 

अंत में, यदि आप सिर्फ तो क्या आप क्या करना चाहते निजी करने के लिए उदाहरण के लिए यह निर्धारित करने के लिए है कंसोल पर उम्र का प्रिंट आउट करना चाहते हैं, अपने विधि केवल वास्तव में एक बात करना चाहिए और इस तरह उसके अनुसार नाम दिया जाना चाहिए:

public void printAgeToConsole(){ 
    System.out.println("Age: " + age); 
} 

void इंगित करता है कि यह विधि कुछ करता है, लेकिन कुछ भी वापस नहीं करता है।

2

निर्माता है सार्वजनिक कक्षा() { चर यू चर प्रकार है कि यू चाहते हैं कि शून्य बदल सकते हैं की जरूरत है कि निर्माता के नीचे जा रहा है सार्वजनिक शून्य methodName() {} पूरी कक्षा विधि में इस्तेमाल होने के लिए परिभाषित विधि विशिष्ट प्रकार वापस।

2

आपका पहला उदाहरण एक सार्वजनिक कन्स्ट्रक्टर है जिसे आप वास्तव में पिल्ला बनाते हैं। आमतौर पर, निर्माता बजाय इसे प्रदर्शित करने और इसे दूर फेंक के नाम की बचत होगी, ताकि आप इसे बाद से देख सकता है, उदाहरण के लिए:

public class Puppy{ 
    private String puppyName; 

    public Puppy(String name){ 
     puppyName = name; 
    } 
    public void bark(){ 
     System.out.println(puppyName + ": woof!"); 
    } 
    ... 
} 
... 
public static void main(){ 
    Puppy Spot = new Puppy("Spot"); // here, the constructor is called, which saves the name 
            // "Spot" into the variable Spot.puppyName. 

    Puppy Fido = new Puppy("Fido"); // on this line, the constructor is called again, but this time, the string 
            // "Fido" is saved into Fido.puppyName. 

    Spot.bark();     // output: "Spot: woof!" 
} 

मैं एक विधि के रूप में एक निर्माता के बारे में सोच है कि "रिटर्न" एक पिल्ला ऑब्जेक्ट, यही कारण है कि इसमें रिटर्न टाइप नहीं है। विधियों और चर जिन्हें स्थिर घोषित किया जाता है, पिल्ला के नाम के विपरीत, विशेष रूप से किसी भी वस्तु से "संबंधित" नहीं होते हैं, लेकिन कक्षा के सभी सदस्यों के बीच साझा किए जाते हैं।

public class Puppy{ 
    ... 
    private static String latinName; 
    public static void setLatinName(String newLatinName){ 
     latinName = newLatinName; 
    } 
    public static void printLatinName(){ 
     System.out.println("I am a " + latinName + "."); 
    } 
}; 
... 
static void main(){ 
    Puppy Spot("Spot"); 
    Puppy Fido("Spot"); 
    Spot.setLatinName("Canis Lupus"); 
    Fido.setLatinName("Canis Lupus Familiaris"); 

    Spot.printLatinName(); // output: "I am a Canus Lupus Familiaris." 
    // even though we used the Fido object to change the latinName string, 
    // the output of Spot's non-static method still reflects the change because 
    // latinName is a static field: there is only one String latinName 
    // shared among all members of the class. 
} 

आप एक पिल्ला वस्तु उपयोग कर सकते हैं स्थिर तरीकों (यदि पिल्ला एक बहुरूपी कुत्ते थे जो विशेष रूप से उपयोगी हो सकता है) कॉल करने के लिए, इसका विपरीत भी सही नहीं है!

public class Puppy{ 
    ... 
    public static void bark(){ 
     System.out.println(puppyName + ": woof!"); // this will not compile! 
    } 
} 

यह अवैध है (और मतलब नहीं है) एक स्थिर समारोह के संदर्भ में गैर स्थिर डेटा सदस्यों को संदर्भित करने के! एक स्थिर कार्य स्थिर चर के समान होता है: सभी सदस्य वस्तुओं के बीच साझा की गई फ़ंक्शन की केवल एक प्रति होती है। इसका मतलब है कि आप पिल्ला को कॉल कर सकते हैं।setLatinName() (Spot.setLatinName() के बजाय)। स्थिर फ़ंक्शन को कॉल करने के लिए आपको किसी विशिष्ट पिल्ला ऑब्जेक्ट का उपयोग करने की आवश्यकता नहीं है: किसी स्थैतिक फ़ंक्शन की गारंटी है कि किसी गैर-स्थैतिक सदस्य चर पर निर्भर न हो (क्योंकि इसमें कोई नहीं है)। Puppy.bark() को कॉल करना समझ में नहीं आता है क्योंकि वर्ग "पिल्ला" में पिल्ला नाम नहीं है; प्रत्येक व्यक्ति पिल्ला का अपना पिल्ला नाम होता है।

मुझे उम्मीद है कि इससे मदद मिलती है। ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग बहुत शक्तिशाली है और मूल बातें समझना महत्वपूर्ण है! सौभाग्य।

संबंधित मुद्दे