2011-03-03 7 views
23

एक सहकर्मी (जो जावा के लिए बहुत नया है) आज बंद हो गया और पूछा कि एक बहुत ही सरल सवाल की तरह क्या लग रहा था। दुर्भाग्य से, मैंने उसे समझाए जाने की कोशिश करने का एक बहुत ही भयानक काम किया।आप अपनी परिभाषा के भीतर कक्षा को क्यों स्थापित कर सकते हैं?

class XCopy { 

    public static void main(String[] args) { 
     XCopy x = new XCopy(); // 1 
     x.doIt(); 
    } 

    public void doIt() { 
     // Some code... 
    } 
} 

वह लाइन 1. क्या उन्हें पता चला था चाहता था क्यों XCopy का एक नया उदाहरण वर्ग XCopy की परिभाषा के भीतर बनाया जा सकता है पर उलझन में था: वह एक किताब है कि एक छोटे से कोड है कि इस तरह देखा था । उन्होंने सोचा कि इससे किसी प्रकार की अग्रेषण संदर्भ त्रुटि होगी। आखिरकार, हमने अभी तक यह घोषणा पूरी नहीं की थी कि कक्षा XCopy क्या था, तो हम एक कैसे बना सकते हैं?

मुझे निश्चित रूप से पता है कि यह वैध कोड है, लेकिन जब मैंने उसे समझाने की कोशिश की, तो मैंने खुद को जवाब पर ठोकर खाई और मुझे डर है कि मैंने उसे शुरू होने से ज्यादा भ्रमित कर दिया। मैं कुछ अन्य स्पष्टीकरण सुनना चाहता हूं कि यह क्यों काम करता है।

कोई विचार? कक्षा की परिभाषा के भीतर आप कक्षा के उदाहरण को तुरंत क्यों शुरू कर सकते हैं?

उत्तर

32

आप संकलन समय पर कक्षा, उसके सभी क्षेत्रों और विधियों आदि को परिभाषित कर रहे हैं। उदाहरण रनटाइम तक नहीं बनाया गया है। तो कोई विरोधाभास नहीं है, जब तक आप लाइन # 1 तक पहुंच जाते हैं तब कक्षा पूरी तरह परिभाषित होती है।

जैसा कि अन्य इंगित करते हैं, क्योंकि main विधि static है, आप ऑब्जेक्ट को तत्काल किए बिना लाइन # 1 तक पहुंच जाएंगे, लेकिन आप बिना किसी समस्या के ऐसा कर सकते हैं। मैं एक-कक्षा प्रयोगों के लिए हर समय इस पैटर्न का उपयोग करता हूं।

+1

'एक-कक्षा प्रयोग' क्या हैं? – Andru

+2

@Andru यह तब होता है जब आप भाषा के साथ प्रयोग कर रहे होते हैं, और आप एक संपूर्ण कार्यक्रम नहीं बनाना चाहते हैं, इसलिए आप सब कुछ एक वर्ग में डाल दें, जिसमें मुख्य विधि – Eames

+0

@Mathew शामिल है, मैं बस अपने ज्ञान को फिर से जांचना चाहता हूं यानी वर्ग को स्मृति में पहले लोड किया जाता है और फिर स्थैतिक मुख्य कहा जाता है, है ना? – light

1

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

इस प्रकार, doIt विधि को गैर स्थैतिक बनाने के लिए, किसी को उस वर्ग का एक उदाहरण बनाना चाहिए जो इसे रखता है।

1

जब भी यह पहले उल्लिखित होता है तो जेवीएम वर्ग को लोड करता है। फिर तत्कालता को रोकने के लिए कुछ भी नहीं है - यह पहले ही लोड हो चुका है

+0

वास्तव में प्रासंगिक है। एक वर्ग एक गैर-स्थैतिक विधि के भीतर स्वयं का एक उदाहरण भी बना सकता है। कोई अंतर्निहित कारण नहीं है कि आप ऑब्जेक्ट को उसी प्रकार की दूसरी वस्तु क्यों नहीं बना सकते हैं।जैसे, कल कल मैंने एक ऑब्जेक्ट के लिए एक फ़ंक्शन लिखा था जिसे मैंने "आधी रात" नामक दिनांक/समय का प्रतिनिधित्व किया है, और यह कॉलिंग ऑब्जेक्ट के समान तारीख के साथ उसी कक्षा का एक और उदाहरण देता है लेकिन समय हाल ही में वापस ले जाता है मध्यरात्रि, यानी माईडेट ("2011-01-01 08:30:00")। आधी रात() प्रभावी ढंग से मायडेट ("2011-01-01 00:00:00") लौटाता है। – Jay

+0

@ जे हाँ, मुझे नींद आनी चाहिए। अब मेरे उत्तर का प्रासंगिक हिस्सा बनाए रखा – Bozho

5

यह सी/सी ++ भावना में आगे का संदर्भ नहीं है। आपकी मुख्य विधि क्लास को अपने संदर्भ के अंदर एक प्रकार के रूप में संदर्भित कर रही है। आप कुछ भी "आगे" नहीं हैं।

public class Foo 
{ 
    private String x; 

    public Foo(String x) { this.x = x; } 
    public Foo(Foo f) { this.x = f.x; } // copy constructor; still compiles fine, even without static 
} 

एक अंतर यह संकलन और जोड़ने है:

तथ्य यह है कि मुख्य स्थिर है, क्योंकि यह अभी भी गैर-स्थिर तरीकों के लिए भी काम करेंगे, सार्थक नहीं है। सी/सी ++ में अलग संकलन और लिंकिंग चरण हैं। जावा में एक क्लास लोडर है। मुझे लगता है कि क्लास लोडर का उपयोग करके रनटाइम पर आवश्यक बाइट कोड और लोडिंग के लिए संकलन जावा और सी/सी ++ के बीच एक सूक्ष्म अंतर है जो बताता है कि आगे संदर्भ विचार की आवश्यकता क्यों नहीं है, लेकिन मैं निश्चित नहीं हूं।

12

क्योंकि कोड पहले संकलित किया गया है, और बाद में निष्पादित किया गया है। सभी संकलक को उस पंक्ति को मान्य करने के लिए जानना आवश्यक है कि एक्सकॉपी नामक एक वर्ग मौजूद है, और इसमें कोई तर्क-तर्ककर्ता नहीं है। कक्षा के बारे में सबकुछ जानने की जरूरत नहीं है।

3

इसी कारण से आप पंक्ति 42 पर एक विधि को कॉल कर सकते हैं जिसे लाइन 78 तक परिभाषित नहीं किया गया है? जावा एक स्क्रिप्टिंग भाषा नहीं है, इसलिए चीजों को इस्तेमाल करने से पहले घोषित नहीं किया जाना चाहिए (यह वास्तव में कुछ स्क्रिप्टिंग भाषाओं के बारे में भी सच है)। संकलन समय पर कक्षा परिभाषा पूरी तरह से माना जाता है।

तुम भी अपने स्वयं के निर्माता में एक वर्ग की एक वस्तु का दृष्टांत कर सकते हैं:

public class Test { 
    Test a; 

    Test() { 
     a = new Test(); 
    } 

    public static void main(String[] args) { 
     System.out.println(new Test()); 
    } 
} 

यह पैदा करता है ... इसके लिए प्रतीक्षा करें ... एक java.lang.StackOverflowError

4

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

public class Foo { 
    // only I get to create new instances 
    private Foo() { 
    } 

    // but you can get instances through this factory method 
    public static Foo createFoo() { 
     return new Foo(); 
    } 
} 
+0

अच्छा सरल वास्तविक जीवन उदाहरण! मैं क्या देख रहा था! – Andru

3

अपने सहकर्मी एक सी या पास्कल प्रोग्रामिंग पृष्ठभूमि इस सवाल abolutely तार्किक है से आ रही है, तो:

यह जहां निर्माता सार्वजनिक नहीं होना चाहिए उदाहरण कक्षाओं में एक कारखाने तरीका प्रदान करने के लिए आम के लिए है। एक सी प्रोग्राम विधियों में उस रेखा से ऊपर घोषित किया जाना चाहिए जहां उनका पहले उपयोग किया जाता है। इसकी हमेशा व्यावहारिक इस क्रम में कार्यों ऑर्डर करने के लिए नहीं हैं, वहाँ हैं कि सिर्फ तरीकों का नाम, वापसी प्रकार और मापदंडों समारोह शरीर को परिभाषित करने के बिना दे:

// forward declaration 
void doSomething(void); 

void doSomethingElse(void) { 
    doSomething(); 
} 

// function definition 
void doSomething(void) { 
    ... 
} 

यह एक पार्सर के निर्माण को आसान बनाने के लिए किया गया था और तेजी से पार्सिंग की अनुमति देने के लिए स्रोत पर कम गुजरने की आवश्यकता है। जावा में हालांकि, पहचानकर्ताओं को परिभाषा के बिंदु से पहले उपयोग करने की अनुमति है। इसके लिए कई चरणों में पार्सिंग होनी है। स्रोत कोड के अनुरूप एक वाक्यविन्यास पेड़ के निर्माण के बाद, इस पेड़ को कक्षाओं या विधियों की सभी परिभाषाओं को निर्धारित करने के लिए पार किया जाता है। विधि निकायों को बाद के चरण में संसाधित किया जाता है, जब दायरे में नामों के बारे में सभी जानकारी ज्ञात होती है।

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

+0

इसमें कोई संदेह नहीं था कि जावा डिजाइनर सी डिजाइनरों के विपरीत संकलक पर काम कर रहे थे जब अधिक संगठनात्मक समूह थे। :) [Conway's Law] (https://en.wikipedia.org/wiki/Conway%27s_law) –

-1

कक्षा को क्लासलोडर द्वारा स्मृति में लोड किया गया है और यदि निम्न में से कोई भी होता है तो प्रारंभ किया जाता है।

1) कक्षा का एक उदाहरण या तो नया() कीवर्ड या class.forName() का उपयोग करके प्रतिबिंब का उपयोग करके बनाया गया है, जो जावा में ClassNotFoundException को फेंक सकता है।

2) कक्षा की एक स्थिर विधि लागू की जाती है।

3) कक्षा का एक स्थिर क्षेत्र असाइन किया गया है।

4) कक्षा का एक स्थिर क्षेत्र उपयोग किया जाता है जो स्थिर चर नहीं है।

5) यदि कक्षा शीर्ष स्तर की कक्षा है और वर्ग के भीतर निहित रूप से घिरा हुआ एक जोरदार बयान निष्पादित किया जाता है।

इसलिए लाइन 1 के द्वारा, कक्षा दोनों लोड और प्रारंभिक है और इसलिए कक्षा में एक उदाहरण को तुरंत चालू करने में कोई समस्या नहीं है।

लेकिन अपने कोड इस तरह है अगर,

class Test { 
    Test test2 = new Test(); 
    public static void main(String[] args) { 
     Test test1 = new Test();  
    } 
} 

the above code will result in stackoverflow exception. 



class Test { 
    public static void main(String[] args) { 
     Test test = new Test();  
    } 
} 

In the above code creating an instance won't call main again. 
Remember, main is a static method, not tied to any particular instance. 



class Test { 
    static Test test2 = new Test(); 
    public static void main(String[] args) { 
     Test test1 = new Test();  
    } 
} 

This code will also run fine. 

और पढ़ें से https://javarevisited.blogspot.in/2012/07/when-class-loading-initialization-java-example.html

नहीं
संबंधित मुद्दे