2016-01-15 4 views
73

मैं एक परीक्षा के लिए अभ्यास कर रहा हूं, और एक नमूना समस्या मिली जो मुझे समझ में नहीं आ रही है।बराबर विधि से संबंधित जावा कोड

निम्न कोड के लिए, लगता है क्या उत्पादन होता है:

public class Test { 

    private static int count = 0; 

    public boolean equals(Test testje) { 
     System.out.println("count = " + count); 
     return false; 
    } 

    public static void main(String [] args) { 
     Object t1 = new Test(); 
     Object t2 = new Test(); 
     Test t3 = new Test(); 
     Object o1 = new Object(); 

     ++count; t1.equals(t2); 
     ++count; t1.equals(t3); 
     ++count; t3.equals(o1); 
     ++count; t3.equals(t3); 
     ++count; t3.equals(t2); 
    } 
} 

इस कोड के उत्पादन में count = 4 है, लेकिन मैं क्यों समझ में नहीं आता। क्या कोई मेरी मदद कर सकता है?

+31

"इस तरह के कोड को क्या करता है" का सही उत्तर होना चाहिए "बहुत चालाक प्रोग्रामर निकाल दिया जाता है।" – fluffy

+0

मैं आधुनिक जावा से बहुत परिचित नहीं हूं, क्या आप चतुरता @fluffy को इंगित कर सकते हैं? – Daniel

+0

@ डैनियल ईरान के उत्तर को देखते हैं - विधि उद्देश्य पैरामीटर के कॉल-साइट प्रकार के आधार पर इसका बहुत अलग व्यवहार है, एक उद्देश्यपूर्ण भ्रमित विधि अधिभार के लिए धन्यवाद। – fluffy

उत्तर

111

पहली बात ध्यान रखना चाहिए कि public boolean equals(Test testje), के बाद से तर्क Test बजाय Object है नहीं ओवरराइड Object के equals करता है, इसलिए हस्ताक्षर मेल नहीं खाते।

इसलिए main विधि ठीक एक बार equals(Test testje) कॉल - जब t3.equals(t3); क्रियान्वित - के बाद से है कि केवल मामला है जिसमें दोनों उदाहरण equals के स्थिर प्रकार के लिए क्रियान्वित किया जाता है और तर्क के प्रकार Test वर्ग के हैं।

t3.equals(t3); चौथा equals कथन (जो स्थैतिक count चर के 4 increments के बाद आता है), इसलिए 4 मुद्रित है।

अन्य सभी equals कथन Object के equals निष्पादित करते हैं, और इसलिए कुछ भी प्रिंट नहीं करते हैं।

एक अधिक विस्तृत विवरण:

t1.equals() कॉल Object के equals तर्क के प्रकार की परवाह किए बिना, स्थिर के बाद से (संकलन समय) प्रकार की t1Object है, और Test वर्ग कि विधि पर हावी नहीं होता । Object कक्षा में equals विधि एक Test तर्क के साथ नहीं है, इसलिए को t1 के गतिशील (रनटाइम प्रकार) के बावजूद, कॉल नहीं किया जा सकता है।

t3.equals() निष्पादित कर सकते हैं या तो Object के equals या Test के बराबर होती है, के बाद से t3 का संकलन समय प्रकार Test है, और Test वर्ग दो equals तरीकों (एक Object वर्ग से विरासत में मिली और अन्य Test में परिभाषित किया गया है कक्षा)।

विधि चुने जाने के तर्क का संकलन समय प्रकार पर निर्भर करता: 1. जब तर्क Object (t3.equals(o1); या t3.equals(t2); के रूप में) है, Object के equals कहा जाता है और कुछ भी नहीं छपा है। 2. जब तर्क Test है, t3.equals(t3); में, equals दोनों संस्करणों का तर्क उस तर्क से मेल खाता है, लेकिन विधि अधिभार के नियमों के कारण, सबसे विशिष्ट तर्क के साथ विधि - equals(Test testje) - चुना गया है और count चर मुद्रित किया गया है।

+19

गीज़, यही कारण है कि मैं @ ओवरराइड एनोटेशन –

11

टेस्ट में बराबर विधि टेस्ट का एक उदाहरण लेता है।

सभी पिछले प्रयास वस्तु का एक उदाहरण है, जो वस्तु वर्ग से inherrited विधि लेने के साथ बनाया गया है:

public boolean equals(Object o){ 
    return this == o; 
} 

के बाद से वहाँ वहाँ में कोई प्रिंट है, यह किसी भी मूल्य मुद्रित नहीं होंगे।

आपका ++count; जब आप वास्तव में अपने

public boolean equals(Test testje){... 

विधि, कॉल गिनती का मूल्य है, इसलिए इस समय में भी वृद्धि होगी है कि मूल्य प्रिंट, गिनती का मूल्य 4.

7

t3.equals(t3) है केवल एक पंक्ति जिसमें सही तर्क हैं जो विधि हस्ताक्षर public boolean equals (Test testje) से मेल खाते हैं, इसलिए यह प्रोग्राम में एकमात्र पंक्ति है जो वास्तव में उस प्रिंट स्टेटमेंट को कॉल करती है। यह प्रश्न आपको कुछ चीजें सिखाने के लिए डिज़ाइन किया गया है।

  • सभी वर्ग परोक्ष वस्तु का विस्तार
  • Object.java एक विधि है जो ऑब्जेक्ट प्रकार
  • एक ही नाम के साथ कई तरीकों लेता है प्रदान की मौजूद कर सकते हैं वे अलग अलग तर्क है के बराबर होती है शामिल हैं - इस विधि ओवरलोडिंग
  • के रूप में जाना जाता है
  • विधि विधि ओवरलोड जो हस्ताक्षर है रनटाइम पर तर्कों से मेल खाता है वह तरीका है जो लागू होता है।

अनिवार्य रूप से यह चाल यह है कि टेस्ट पूरी तरह से सभी जावा वर्गों की तरह ऑब्जेक्ट बढ़ाता है। ऑब्जेक्ट में एक समान विधि होती है जो ऑब्जेक्ट टाइप करती है। टी 1 और टी 2 टाइप किए गए हैं कि रन टाइम पर तर्क परीक्षण में परिभाषित बराबर के विधि हस्ताक्षर से मेल नहीं खाते हैं। इसके बजाय यह हमेशा ऑब्जेक्ट.जावा में बराबर विधि में कॉल कर रहा है क्योंकि या तो आधार प्रकार वस्तु है जिसमें ऑब्जेक्ट.जावा या व्युत्पन्न प्रकार में परिभाषित एकमात्र विधियां हैं, ऑब्जेक्ट

public boolean equals(Test testje) 

दर्ज नहीं किया जा सकता है क्योंकि उस मामले में रनटाइम पर तर्क ऑब्जेक्ट का प्रकार है जो टेस्ट का सुपरक्लास है, उप-वर्ग नहीं है। तो बजाय यह Test.java के परोक्ष टाइप किया सुपर क्लास Object.java में बराबर विधि जो भी एक विधि है, जो सिर्फ

public boolean equals (Object o) 

की एक विधि हस्ताक्षर जो इस मामले में हमारे तर्क से मेल करने के लिए होता है के बराबर होती है शामिल हैं पर लग रहा है रनटाइम तो यह विधि बराबर है जो निष्पादित करता है।

t3.equals(t3) के मामले में नोटिस बेस प्रकार और व्युत्पन्न प्रकार के टी 3 दोनों टेस्ट हैं।

Test t3 = new Test(); 

इसका मतलब है कि रनटाइम पर आप Test.java में बराबर विधि और तर्क आप में से गुजर रहे हैं बुला रहे हैं प्रकार टेस्ट के वास्तव में है, इसलिए विधि हस्ताक्षर मैच और Test.java अंदर कोड निष्पादित करता है। इस बिंदु पर count == 4। आप के लिए ज्ञान के

बोनस बिट:

@Override 

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

4

दो महत्वपूर्ण चीजें हैं जिन्हें आपको जानना चाहिए।

  • ओवरराइड विधियों के पास उनके सुपरक्लास के रूप में सटीक हस्ताक्षर होना चाहिए। (आपके उदाहरण में यह स्थिति पूरी नहीं होती है।)

  • किसी ऑब्जेक्ट के लिए जावा में, हमारे पास दो प्रकार हैं: compile type and runtime type। निम्नलिखित उदाहरण में संकलित प्रकार myobjObject है लेकिन इसका रनटाइम प्रकार Car है।

    public class Car{ 
         @Override 
         public boolean equals(Object o){ 
          System.out.println("something"); 
          return false; 
         } 
    } 
    

    Object myobj = new Car();

    इसके अलावा, आप ध्यान देना चाहिए कि myobj.equals(...) परिणाम कंसोल में something मुद्रण में।

+1

@ ओवरराइड की आवश्यकता नहीं है, हेक यह 1.5 – plugwash

+0

@plugwash तक बिल्कुल मौजूद नहीं था। आपको @ ओवरराइड की आवश्यकता नहीं है। असल में इस मामले में यदि आप @ ओवरराइड कोड जोड़ते हैं तो संकलन बंद हो जाएगा क्योंकि सुपर विधि में समान विधि हस्ताक्षर के साथ कोई 'बराबर' विधि नहीं है। @ ओवरराइड एनोटेशन संकलक को बताना है कि इस सटीक विधि हस्ताक्षर के साथ सुपरक्लास में कुछ होना चाहिए - कृपया शिकायत करें कि इस विधि का उद्देश्य वास्तव में उद्देश्य पर कुछ ओवरराइड करने का इरादा है ' –

+0

@plugwash आप सही हैं, मेरे संपादित जवाब। –

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