जावा को ओवरराइड करना () विधि - काम नहीं कर रहा है?


150

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

पूर्णता के लिए, मैं एक आईडीई या डिबगर का उपयोग नहीं कर रहा था - बस अच्छे पुराने जमाने के टेक्स्ट एडिटर और सिस्टम.आउट्स। समय बहुत सीमित था और यह एक स्कूल परियोजना थी।

किसी भी तरह -

मैं एक बुनियादी खरीदारी की टोकरी जो एक हो सकता है विकसित कर रहा था ArrayListकी Bookवस्तुओं । आदेश लागू करने के लिए addBook(), removeBook()और hasBook()गाड़ी के तरीकों, मैं अगर जाँच करने के लिए चाहता था Bookपहले से ही अस्तित्व में Cart। इसलिए मैं जाता हूँ -

public boolean equals(Book b) {
    ... // More code here - null checks
    if (b.getID() == this.getID()) return true;
    else return false;
}

सभी परीक्षण में ठीक काम करता है। मैं 6 ऑब्जेक्ट बनाता हूं और उन्हें डेटा से भरता हूं। कई Cartकाम करता है , हटाता है, () पर काम करता है और सब कुछ ठीक काम करता है। मैंने पढ़ा कि आप या तो होequals(TYPE var)equals(Object o) { (CAST) var } सकते हैं या यह मान लें कि चूंकि यह काम कर रहा था, इसलिए यह बहुत ज्यादा मायने नहीं रखता था।

तब मैं कोई समस्या हुई थी - मैं एक बनाने के लिए आवश्यक Bookके साथ वस्तु केवलID बुक वर्ग के भीतर से उस में। इसमें कोई अन्य डेटा दर्ज नहीं किया जाएगा। मूल रूप से निम्नलिखित हैं:

public boolean hasBook(int i) {
    Book b = new Book(i);
    return hasBook(b);
}

public boolean hasBook(Book b) {
    // .. more code here
    return this.books.contains(b);
}

अचानक, equals(Book b)विधि अब काम नहीं करती है। यह एक अच्छा डीबगर के बिना नीचे ट्रैक करने के लिए एक बहुत लंबा समय लगा और Cartवर्ग को ठीक से परीक्षण और सही मान लिया गया। equals()निम्नलिखित के लिए विधि को स्वैप करने के बाद:

public boolean equals(Object o) {
    Book b = (Book) o;
    ... // The rest goes here   
}

सब कुछ फिर से काम करने लगा। क्या कोई कारण है कि विधि ने पुस्तक पैरामीटर को नहीं लेने का फैसला किया, भले ही यह स्पष्ट रूप से एक Bookवस्तु थी? एकमात्र अंतर यह प्रतीत होता था कि यह एक ही वर्ग के भीतर से तात्कालिक था, और केवल एक डेटा सदस्य से भरा था। मैं बहुत भ्रमित हूं। कृपया, कुछ प्रकाश डाला?


1
मुझे पता है कि मैंने चिंतनशील होकर बराबरी के तरीकों को ओवरराइड करने के संबंध में 'कॉन्ट्रैक्ट' का उल्लंघन किया था - हालांकि मुझे यह जांचने के लिए एक त्वरित तरीके की आवश्यकता थी कि क्या वस्तु जेनरिक का उपयोग किए बिना ArrayList में मौजूद थी।
जोश स्मेटन

1
जावा और बराबरी के बारे में जानने के लिए यह एक अच्छा सबक है
jjnguy

जवाबों:


329

जावा में, जिस equals()विधि से विरासत में मिला Objectहै:

public boolean equals(Object other);

दूसरे शब्दों में, पैरामीटर प्रकार का होना चाहिए Object। इसे ओवरराइडिंग कहा जाता है ; आपकी विधि public boolean equals(Book other)वह करती है जिसे विधि को अधिभार कहा जाता है equals()

सामग्री (जैसे इसके और तरीकों के लिए) की तुलना करने के लिए ArrayListओवरराइड equals()तरीकों का उपयोग करता है , न कि ओवरलोड वाले। आपके अधिकांश कोड में, जो ठीक से ओवरराइड नहीं करता था, उसे कॉल करना ठीक था, लेकिन इसके अनुरूप नहीं था ।contains()equals()ObjectArrayList

इसलिए, सही तरीके से ओवरराइड न करने से समस्याएँ हो सकती हैं।

मैं ओवरराइड करता है निम्नलिखित हर समय के बराबर:

@Override
public boolean equals(Object other){
    if (other == null) return false;
    if (other == this) return true;
    if (!(other instanceof MyClass)) return false;
    MyClass otherMyClass = (MyClass)other;
    ...test other properties here...
}

@Overrideएनोटेशन का उपयोग एक टन को मूर्खतापूर्ण गलतियों के साथ मदद कर सकता है।

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


31
@ ऑवरराइड एनोटेशन के पक्ष में यह एक अच्छा तर्क है ... अगर ओपी ने @ ऑवरराइड का उपयोग किया होता तो उनके कंपाइलर ने उन्हें बताया होता कि वह वास्तव में पैरेंट क्लास मेथड को ओवरराइड नहीं कर रहे थे ...
कोवान

1
@ ऑवरराइड के बारे में कभी पता नहीं था, इसके लिए धन्यवाद! मैं उस ओवरशाइडिंग हैशकोड () को भी जोड़ना चाहता हूं जो वास्तव में किया जाना चाहिए था और जल्द ही त्रुटि देखी जा सकती थी।
जोश स्मेटन

5
कुछ IDE (जैसे ग्रहण) वर्ग सदस्य चर के आधार पर आपके लिए भी (और) हैशकोड () विधियों को ऑटोजेनरेट कर सकते हैं।
स्के।

1
if (!(other instanceof MyClass))return false;रिटर्न falseअगर MyClassअन्य वर्ग का विस्तार करता है। लेकिन falseअगर दूसरी कक्षा आगे बढ़ती तो यह वापस नहीं आता MyClassequalकम विरोधाभासी नहीं होना चाहिए ?
रॉबर्ट

19
Instof का उपयोग करते समय पिछला अशक्त निरर्थक है।
माटुस्स डिमज़िक

108

यदि आप ग्रहण का उपयोग करते हैं तो शीर्ष मेनू पर जाएं

स्रोत -> समान उत्पन्न () और हैशकोड ()


मैं सहमत हूँ! यह एक जिसे मैं पहले कभी नहीं जानता था और इसे उत्पन्न करने से यह कम त्रुटि वाला होता है
बॉय

मुझे भी। धन्यवाद फ्रेड!
आइल

16
IntelliJ में आपको यह कोड → Generate… या control + N के अंतर्गत मिलता है। :)
right:

Netbeans में आप मेनू बार> सोर्स (या राइट क्लिक)> इन्सर्ट कोड (या Ctrl-I) पर जाएं, और Generate equals () ... पर क्लिक करें
सोलोमन

11

अपने प्रश्न के लिए थोड़ा-विषय, लेकिन यह शायद वैसे भी उल्लेख के लायक है:

कॉमन्स लैंग को कुछ बेहतरीन तरीके मिले हैं जिनका उपयोग आप बराबरी और हैशकोड को ओवरराइड करने में कर सकते हैं। की जाँच करें EqualsBuilder.reflectionEquals (...) और HashCodeBuilder.reflectionHashCode (...) । अतीत में मुझे बहुत सिरदर्द हुआ - बेशक, अगर आप आईडी पर "बराबर" करना चाहते हैं तो यह आपकी परिस्थितियों के अनुकूल नहीं हो सकता है।

मैं यह भी मानता हूं कि @Overrideजब भी आप बराबरी (या किसी अन्य विधि) से ओवरराइड कर रहे हों, तो आपको एनोटेशन का उपयोग करना चाहिए ।


4
यदि आप एक right click -> source -> generate hashCode() and equals()
ग्रहणशील

1
क्या मैं सही हूं कि इन पद्धति को रनटाइम पर निष्पादित किया जाता है? यदि हम प्रतिबिंब के कारण किसी अन्य वस्तु की समानता के लिए उनकी जाँच कर रहे आइटम के साथ एक बड़ा संग्रह ट्रेस कर रहे हैं तो क्या हमारे पास प्रदर्शन के मुद्दे नहीं होंगे?
गकेट

4

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

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{

    private long        errorNumber;
    private int         numberOfParameters;
    private Level       loggingLevel;
    private String      messageCode;

बराबरी में उपयोग करने के लिए फ़ील्ड को अनुकूलित करने के लिए उपलब्ध विकल्पों को देखें । लवनोक मावेन में हिमस्खलन है । बस इसे प्रदान की गई गुंजाइश के साथ जोड़ें :

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.14.8</version>
    <scope>provided</scope>
</dependency>

1

एंड्रॉइड स्टूडियो में ऑल्ट + इंसर्ट ---> बराबर होता है और हैशकोड

उदाहरण:

    @Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Proveedor proveedor = (Proveedor) o;

    return getId() == proveedor.getId();

}

@Override
public int hashCode() {
    return getId();
}

1

विचार करें:

Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...

1
@Elazar ऐसा कैसे? objके रूप में घोषित किया गया है Object। विरासत का मुद्दा यह है कि आप एक निर्दिष्ट कर सकते हैं Bookकरने के लिए obj। उसके बाद, जब तक आप यह सुझाव Objectनहीं देते हैं कि एक के Stringमाध्यम से तुलना नहीं की जानी चाहिए equals(), यह कोड पूरी तरह से कानूनी और वापस होना चाहिए false
bcsb1001

मैं बिल्कुल सुझाव देता हूं। मेरा मानना ​​है कि यह बहुत व्यापक रूप से स्वीकार किया जाता है।
एलजार

0

instanceOfबयान अक्सर बराबरी के कार्यान्वयन में प्रयोग किया जाता है।

यह एक लोकप्रिय नुकसान है!

समस्या यह है कि instanceOfसमरूपता के नियम का उल्लंघन करते हुए :

(object1.equals(object2) == true) यदि और केवल यदि (object2.equals(object1))

यदि पहली बराबरी सही है, और ऑब्जेक्ट 2 उस वर्ग के उपवर्ग का एक उदाहरण है, जहां obj1 का संबंध है, तो दूसरा बराबर गलत होगा!

यदि माना हुआ वर्ग जहाँ ob1 का है, अंतिम रूप में घोषित किया गया है, तो यह समस्या उत्पन्न नहीं हो सकती है, लेकिन सामान्य तौर पर, आपको निम्न के रूप में परीक्षण करना चाहिए:

this.getClass() != otherObject.getClass(); यदि नहीं, तो झूठी वापसी करें, अन्यथा समानता के लिए तुलना करने के लिए खेतों का परीक्षण करें!


3
बलोच, प्रभावी जावा, आइटम 8, equals()विधि को ओवरराइड करने के साथ मुद्दों पर चर्चा करने वाला एक बड़ा खंड देखें । वह उपयोग करने के खिलाफ सिफारिश करता है getClass()। मुख्य कारण यह है कि ऐसा करने से उपवर्गों के लिए लिस्कोव सबस्टीट्यूशन सिद्धांत टूट जाता है जो समानता को प्रभावित नहीं करते हैं।
स्टुअर्ट मार्क्स

-1

recordId ऑब्जेक्ट की संपत्ति है

@Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Nai_record other = (Nai_record) obj;
        if (recordId == null) {
            if (other.recordId != null)
                return false;
        } else if (!recordId.equals(other.recordId))
            return false;
        return true;
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.