2013-07-23 6 views
17
//: c07:Sandwich.java 
// Order of constructor calls. 
// package c07; 
// import com.bruceeckel.simpletest.*; 

import java.util.*; 

class Meal { 
    Meal() { System.out.println("Meal()"); } 
} 

class Bread { 
    Bread() { System.out.println("Bread()"); } 
} 

class Cheese { 
    Cheese() { System.out.println("Cheese()"); } 
} 

class Lettuce { 
    Lettuce() { System.out.println("Lettuce()"); } 
} 

class Lunch extends Meal { 
    Lunch() { System.out.println("Lunch()"); } 
} 

class PortableLunch extends Lunch { 
    PortableLunch() { System.out.println("PortableLunch()");} 
} 

public class Sandwich extends PortableLunch { 
// private static Test monitor = new Test(); 
    private Bread b = new Bread(); 
    private Cheese c = new Cheese(); 
    private Lettuce l = new Lettuce(); 
    public Sandwich() { 
    System.out.println("Sandwich()"); 
    } 
    public static void main(String[] args) { 
    new Sandwich(); 
    /* 
    monitor.expect(new String[] { 
     "Meal()", 
     "Lunch()", 
     "PortableLunch()", 
     "Bread()", 
     "Cheese()", 
     "Lettuce()", 
     "Sandwich()" 
    }); 
    // */ 
    } 
} ///:~ 

इस कोड के उत्पादन मेंआदेश जावा में बहुस्तरीय विरासत में कॉल

Meal() 
Lunch() 
PortableLunch() 
Bread() 
Cheese() 
Lettuce() 
Sandwich() 

है के बाद से एक कक्षा में खेतों क्रम में बनाए जाते हैं वे, घोषित किया गया है क्यों

नहीं है
Bread() 
Cheese() 
Lettuce() 

उपरोक्त सूची के शीर्ष पर आते हैं?

इसके अलावा, यह इस कोड में क्या करने का प्रयास कर रहा है?

monitor.expect(new String[] { 
     "Meal()", 
     "Lunch()", 
     "PortableLunch()", 
     "Bread()", 
     "Cheese()", 
     "Lettuce()", 
     "Sandwich()" 
    }); 

पहले मैंने सोचा कि यह एक अज्ञात वर्ग था, लेकिन ऐसा नहीं लगता है। क्या यह एक स्ट्रिंग सरणी शुरू कर रहा है? स्ट्रिंग चर के लिए इसका नाम क्यों नहीं है? कृपया मुझे प्रोग्रामिंग निर्माण का नाम यहां इस्तेमाल किया जा रहा है।

+3

लेकिन क्या यह आपका होमवर्क नहीं है? –

+0

@ क्रिस्टियनमार्क यह निश्चित रूप से होमवर्क नहीं है, जावा में सोच पढ़ने के दौरान मेरे पास एक ही सवाल था। मुझे यह प्रश्न और उत्तर बहुत उपयोगी लगता है :) –

उत्तर

19

निर्माता:

public Sandwich() { 
    super(); // Compiler adds it if it is not explicitly added by programmer 
    // All the instance variable initialization is moved here by the compiler. 
    b = new Bread(); 
    c = new Cheese(); 
    l = new Lettuce(); 

    System.out.println("Sandwich()"); 
} 

तो, एक निर्माता में पहले बयान सुपर वर्ग निर्माता की श्रंखला है:

public Sandwich() { 
    System.out.println("Sandwich()"); 
} 

को संकलक द्वारा अनुवाद किया है। वास्तव में, उस मामले के लिए, सुपर क्लास कन्स्ट्रक्टर को किसी भी कन्स्ट्रक्टर चेन में पहला बयान। यही कारण है कि पहले सुपर क्लास कन्स्ट्रक्टर PortableLunch का आह्वान किया जाता है, जो संकलक (याद रखें?) द्वारा super() के कारण, इसके सुपर क्लास कन्स्ट्रक्टर को कॉल करता है।

कन्स्ट्रक्टर कॉल की यह श्रृंखला विरासत पदानुक्रम के शीर्ष पर कक्षा तक की जाती है, जिससे अंत में Object वर्ग कन्स्ट्रक्टर का आह्वान किया जाता है।

अब, प्रत्येक सुपर क्लास कन्स्ट्रक्टर को निष्पादित करने के बाद, और सभी सुपर क्लास फ़ील्ड शुरू किए गए हैं, तत्काल उप-वर्ग निर्माता super() कॉल के बाद निष्पादन शुरू करते हैं। और फिर अंत में यह Sandwitch() कन्स्ट्रक्टर पर वापस आता है, जो अब आपके फ़ील्ड को प्रारंभ करता है।

तो, मूल रूप से आपके फ़ील्ड अंतिम रूप से आरंभ होते हैं, और इसलिए वे Sandwitch() मुद्रित होने से पहले ही अंत में मुद्रित होते हैं।

उदाहरण निर्माण प्रक्रिया की विस्तृत व्याख्या के लिए JLS - §12.5 - Creation of New Class Instance का संदर्भ लें।


प्रश्न के अपने 2 भाग के लिए के रूप में:

monitor.expect(new String[] { 
     "Meal()", 
     "Lunch()", 
     "PortableLunch()", 
     "Bread()", 
     "Cheese()", 
     "Lettuce()", 
     "Sandwich()" 
    }); 

इस कोड को एक अनाम सरणी पैदा कर रही है, और एक ही समय में यह कुछ स्ट्रिंग शाब्दिक आरंभ। यह एक नामित सरणी बनाने के तरीके के समान है:

String[] arr = new String[] { "rohit", "jain" }; 
+0

बहुत धन्यवाद – user13267

+0

@ user13267। आपका स्वागत है :) –

+0

क्या यह वही मामला होगा यदि वे वस्तुओं के बजाय प्राइमेटिव थे? उदाहरण के लिए, यदि int b = 5 int c = 10 और int l = 15, और 'नया सैंडविच();' नहीं कहा गया था, तो संकलक अभी भी बी, सी और एल के लिए स्मृति आवंटित करेगा? – user13267

5

आपके उदाहरण में वस्तुएं विरासत का उपयोग करती हैं, जो रचनाकारों की एक श्रृंखला कहलाती है। विरासत का उपयोग करते समय किसी अन्य (subtype) से विरासत प्राप्त करने वाले वर्ग को कक्षा के निर्माता को कॉल करना होगा (super type)। जब एक प्रकार का पदानुक्रम मौजूद होता है, जिसका अर्थ है कि कई वर्ग एक श्रृंखला में एक-दूसरे से विस्तारित होते हैं, तो सुपर कन्स्ट्रक्टर की कॉल श्रृंखला में पहली श्रेणी में फैलती है जो किसी अन्य वर्ग (ऑब्जेक्ट को अनदेखा करने) से प्राप्त नहीं होती है।

उप प्रकार के सुपर क्लास कन्स्ट्रक्टर को उप प्रकार के कन्स्ट्रक्टर के निष्पादन से पहले बुलाया जाना चाहिए क्योंकि यह सुपर प्रकारों में फ़ील्ड या विधियों पर भरोसा कर सकता है। कन्स्ट्रक्टर कॉल पदानुक्रम को चेन करता है और एक बार प्रत्येक कन्स्ट्रक्टर ने सबटाइप शुरू करने के बाद इसकी तत्कालता शुरू की है।

एक बार कक्षा प्रकार के पदानुक्रम में सुपर प्रकार के रचनाकारों को उपप्रकार के फ़ील्ड कहा जाता है क्योंकि उन्हें उप प्रकार के निर्माता द्वारा भी आवश्यकता हो सकती है। उप प्रकार के क्षेत्रों को उपप्रकार कन्स्ट्रक्टर निष्पादित करने के बाद घोषित किया जाता है।

यह आदेश आवश्यक है क्योंकि उप प्रकार सुपर प्रकार में स्थापित फ़ील्ड या विधियों पर भरोसा कर सकता है।

Meal() (Top of Class Hierarchy, not including Object) 
Lunch() (Extends Meal) 
PortableLunch() (Extends Lunch) 
Bread() (Field of lunch declared before constructor call) 
Cheese() (Field of lunch declared before constructor call) 
Lettuce() (Field of lunch declared before constructor call) 
Sandwich() (Extends Portable Lunch) 

Here is a really good overview of object creation in Java.

+0

लेकिन 'नया सैंडविच();' मुख्य रूप से टिप्पणी करते हुए; 'इसमें कोई आउटपुट नहीं है। ऐसा क्यों है? रोटी, पनीर और सलाद स्वतंत्र वर्ग हैं। भले ही सैंडविच का एक वस्तु नहीं बनाया गया है, अन्य क्षेत्रों के रचनाकारों को नहीं कहा जाना चाहिए, क्योंकि उन्हें सैंडविच कक्षा में स्पष्ट रूप से घोषित किया गया है? – user13267

+0

@ user13267 लेकिन वे कहां तत्काल हैं? – zEro

+0

@ user13267 Thats क्योंकि किसी भी ऑब्जेक्ट को तत्काल नहीं किया जा रहा है, इसलिए सभी रचनाकारों को कॉल कभी नहीं बनाया जाता है, जिससे सभी प्रिंट स्टेटमेंट कभी नहीं बुलाए जाते हैं। असल में निष्पादन पथ का पालन कभी नहीं किया जाता है जो सभी डीबग संदेशों को प्रिंट करता है। –

1
new String[] { 
     "Meal()", 
     "Lunch()", 
     "PortableLunch()", 
     "Bread()", 
     "Cheese()", 
     "Lettuce()", 
     "Sandwich()" 
    } 

\ ऊपर anonymous array declaration है। आपको इस मामले में आकार निर्दिष्ट करने की आवश्यकता नहीं है।

आपके सभी सुपर क्लास कन्स्ट्रक्टर पहले आपके आवृत्ति चर शुरू करने से पहले लागू किए जाएंगे। यानी,

आदेश --->

Object(), 
    all your superclass constructors, 
    instance variables of this class in that order 
1

निर्माता पहले कहा जाता है, तो इसकी उदाहरण चर मूल्यांकन किया जाता है, Java Language Specification में निर्दिष्ट क्रम के अनुसार। यही कारण है कि आप

Bread() 
Cheese() 
Lettuce() 

के बाद

Meal() 
Lunch() 
PortableLunch() 
String [] आरंभीकरण के बारे में

मिलता है, के रूप में आपको लगता है नहीं है एक गुमनाम वर्ग, बस स्ट्रिंग ऑब्जेक्ट रचना है, जो nesesarily होने की जरूरत नहीं है एक चर को सौंपा गया।

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