जावा में बराबर विधि को ओवरराइड कैसे करें


108

मैं जावा में बराबर पद्धति को ओवरराइड करने की कोशिश कर रहा हूं। मेरे पास एक वर्ग है Peopleजिसमें मूल रूप से 2 डेटा फ़ील्ड हैं nameऔर age। अब मैं equalsविधि को ओवरराइड करना चाहता हूं ताकि मैं 2 लोगों की वस्तुओं के बीच जांच कर सकूं।

मेरा कोड इस प्रकार है

public boolean equals(People other){
    boolean result;
    if((other == null) || (getClass() != other.getClass())){
        result = false;
    } // end if
    else{
        People otherPeople = (People)other;
        result = name.equals(other.name) &&  age.equals(other.age);
    } // end else

    return result;
} // end equals

लेकिन जब मैं लिखता हूं तो age.equals(other.age)यह मुझे त्रुटि देता है क्योंकि बराबरी का तरीका केवल स्ट्रिंग की तुलना कर सकता है और आयु पूर्णांक है।

उपाय

मैंने ==सुझाव के अनुसार ऑपरेटर का उपयोग किया और मेरी समस्या हल हो गई।


3
हे इस बारे में कैसे। :)
डेनिस.सोलोनेंको

1
आयु के लिए डेटा प्रकार क्या है? int या पूर्णांक? इसके अलावा, आप JDK के किस संस्करण का उपयोग कर रहे हैं?
मनीष

2
"के रूप में बराबरी विधि केवल स्ट्रिंग की तुलना कर सकते हैं" - किसने कहा कि बराबर विधि केवल स्ट्रिंग की तुलना कर सकती है? बराबर विधि ऑब्जेक्ट क्लास से संबंधित है और किसी भी वर्ग द्वारा बनाई गई डिफ़ॉल्ट रूप से कार्यान्वयन के बराबर होगी। आप किसी भी जावा वर्ग पर बराबर कॉल कर सकते हैं
मनीष

जवाबों:


127
//Written by K@stackoverflow
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        ArrayList<Person> people = new ArrayList<Person>();
        people.add(new Person("Subash Adhikari", 28));
        people.add(new Person("K", 28));
        people.add(new Person("StackOverflow", 4));
        people.add(new Person("Subash Adhikari", 28));

        for (int i = 0; i < people.size() - 1; i++) {
            for (int y = i + 1; y <= people.size() - 1; y++) {
                boolean check = people.get(i).equals(people.get(y));

                System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
                System.out.println(check);
            }
        }
    }
}

//written by K@stackoverflow
    public class Person {
        private String name;
        private int age;

        public Person(String name, int age){
            this.name = name;
            this.age = age;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }

            
if (obj.getClass() != this.getClass()) {
                return false;
            }



            final Person other = (Person) obj;
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
                return false;
            }

            if (this.age != other.age) {
                return false;
            }

            return true;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
            hash = 53 * hash + this.age;
            return hash;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

आउटपुट:

Daud:

- सुभाष अधिकारी - वीएस - के झूठे

- सुबाष अधकारी - वि। - स्टैकऑवरफ्लो झूठी

- सुबाष अधकारी - वि। - सुबाष अधकारी सच

- के - वीएस - स्टैकऑवरफ्लो झूठी

- के - वीएस - सुबाष अधकारी झूठे

- स्टैकऑवरफ्लो - वीएस - सुबाष अधकारी झूठे

- निर्माण सफलता (कुल समय: 0 सेकंड)


7
hash = 53 * hashआप ऐसा क्यों कर रहे हैं?
किट्टू

2
getClass()यदि वर्ग उप-वर्ग से अलग हो जाता है, और सुपर-क्लास के ऑब्जेक्ट के साथ तुलना करने पर समस्याओं का उपयोग करने जा रहा है।
Tuxdude

1
bcoz 53 प्राइम नंबर हो सकता है , इस उत्तर पर एक नज़र डालें। stackoverflow.com/a/27609/3425489 , उन्होंने टिप्पणी करते हुए कहा कि नंबर चुनते समयhashCode()
शांताराम तुपे

1
इस सवाल पर विजयी उत्तर का एक उत्कृष्ट विवरण है कि आपने
हैशकोड

7
यदि ( instanceofऑपरेटर ) का उपयोग करने के बजाय (getClass ()! = Obj.getClass ()) का उपयोग करने पर विचार करें isAssignableFrom। इसके लिए उप-प्रकार मैच के बजाय सटीक प्रकार के मिलान की आवश्यकता होगी। - सममित आवश्यकता। Stringअन्य ऑब्जेक्ट प्रकारों की तुलना करने के लिए , आप उपयोग कर सकते हैं Objects.equals(this.name,other.name)
योयो

22

एक नए तरीके के हस्ताक्षर का परिचय जो पैरामीटर प्रकारों को बदलता है, ओवरलोडिंग कहलाता है :

public boolean equals(People other){

यहाँ Peopleसे अलग है Object

जब एक विधि हस्ताक्षर अपने सुपरक्लास के समान रहता है, तो इसे ओवरराइडिंग कहा जाता है और @Overrideएनोटेशन संकलन-समय पर दोनों को अलग करने में मदद करता है:

@Override
public boolean equals(Object other){

की वास्तविक घोषणा को देखे बिना age, यह कहना मुश्किल है कि त्रुटि क्यों दिखाई देती है।


18

मैं विवरणों के बारे में निश्चित नहीं हूं क्योंकि आपने पूरे कोड को पोस्ट नहीं किया है, लेकिन:

  • ओवरराइड करने के लिए याद hashCode()के साथ-साथ
  • equalsविधि होना चाहिए Objectनहीं, Peopleअपने तर्क प्रकार के रूप में। इस समय आप ओवरलोडिंग कर रहे हैं, ओवरराइडिंग नहीं कर रहे हैं, बराबरी का तरीका, जो शायद आप नहीं चाहते हैं, विशेष रूप से यह देखते हुए कि आप इसके प्रकार की जांच बाद में करते हैं।
  • आप instanceofयह जाँचने के लिए उपयोग कर सकते हैं कि यह एक पीपल ऑब्जेक्ट हैif (!(other instanceof People)) { result = false;}
  • equalsसभी वस्तुओं के लिए उपयोग किया जाता है, लेकिन आदिम नहीं। मुझे लगता है कि आप का मतलब है कि उम्र एक int(आदिम) है, जिस स्थिति में बस का उपयोग करें ==। ध्यान दें कि एक एँगर (एक पूंजी 'I' के साथ) एक वस्तु है जिसकी तुलना बराबरी से की जानी चाहिए।

देखें क्या मुद्दों पर विचार किया जाना चाहिए जब जावा में बराबरी और hashCode अधिभावी? अधिक जानकारी के लिए।


12
@Override
public boolean equals(Object that){
  if(this == that) return true;//if both of them points the same address in memory

  if(!(that instanceof People)) return false; // if "that" is not a People or a childclass

  People thatPeople = (People)that; // than we can cast it to People safely

  return this.name.equals(thatPeople.name) && this.age == thatPeople.age;// if they have the same name and same age, then the 2 objects are equal unless they're pointing to different memory adresses
}

12

आइटम 10: सामान्य अनुबंध का पालन करें जब बराबर होती है

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

  • कक्षा का प्रत्येक उदाहरण स्वाभाविक रूप से अद्वितीय है । यह थ्रेड्स जैसे वर्गों के लिए सही है जो मूल्यों के बजाय सक्रिय संस्थाओं का प्रतिनिधित्व करते हैं। ऑब्जेक्ट द्वारा प्रदान किए गए समान कार्यान्वयन में इन वर्गों के लिए बिल्कुल सही व्यवहार है।

  • "तार्किक समानता" परीक्षण प्रदान करने के लिए वर्ग की कोई आवश्यकता नहीं है। उदाहरण के लिए, java.util.regex.Pattern को यह जांचने के लिए बराबरी मिल सकती है कि क्या दो पैटर्न उदाहरणों ने एक ही नियमित अभिव्यक्ति का प्रतिनिधित्व किया है, लेकिन डिजाइनरों ने यह नहीं सोचा कि ग्राहकों को इस कार्यक्षमता की आवश्यकता होगी या चाहते हैं। इन परिस्थितियों में, ऑब्जेक्ट से विरासत में मिला समान कार्यान्वयन आदर्श है।

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

  • वर्ग निजी या पैकेज-निजी है , और आप निश्चित हैं कि इसकी बराबरी का तरीका कभी भी लागू नहीं होगा। यदि आप बहुत जोखिम-से-प्रभावित हैं, तो आप यह सुनिश्चित करने के लिए बराबरी के तरीके को ओवरराइड कर सकते हैं कि यह गलती से लागू नहीं हुआ है:

equalsविधि एक तुल्यता संबंध लागू करता है। इसके ये गुण हैं:

  • रिफ्लेक्टिव: किसी भी गैर-शून्य संदर्भ मूल्य के लिए x, x.equals(x)सही लौटना चाहिए।

  • सममित: किसी भी गैर-शून्य संदर्भ मानों के लिए xऔर y, x.equals(y)यदि केवल y.equals (x) सही है, तो वापस लौटना चाहिए।

  • सकर्मक: किसी भी गैर-शून्य संदर्भ मूल्यों के लिए x, y, z, अगर x.equals(y)रिटर्न trueऔर y.equals(z)रिटर्न true, तो x.equals(z)लौटना चाहिए true

  • सुसंगत: किसी भी गैर-शून्य संदर्भ मूल्यों के लिए xऔर y, x.equals(y)लगातार कई रिटर्न trueया लगातार रिटर्न करना होगा false, बशर्ते कि बराबरी की तुलना में उपयोग की गई कोई भी जानकारी संशोधित न हो।

  • किसी भी गैर-शून्य संदर्भ मान के लिए x, x.equals(null)वापस लौटना चाहिए false

यहाँ एक उच्च गुणवत्ता के बराबर विधि के लिए एक नुस्खा है:

  1. ==यह जाँचने के लिए ऑपरेटर का उपयोग करें कि क्या तर्क इस ऑब्जेक्ट का संदर्भ है। यदि हां, तो सच लौटें। यह सिर्फ एक प्रदर्शन अनुकूलन है, लेकिन एक ऐसा है जो तुलनात्मक रूप से महंगा होने पर करने योग्य है।

  2. instanceofतर्क का सही प्रकार है या नहीं, यह जांचने के लिए ऑपरेटर का उपयोग करें । यदि नहीं, तो झूठे लौटें। आमतौर पर, सही प्रकार वह वर्ग है जिसमें विधि होती है। कभी-कभी, यह इस वर्ग द्वारा लागू किया गया कुछ इंटरफ़ेस है। एक इंटरफ़ेस का उपयोग करें यदि वर्ग एक इंटरफ़ेस लागू करता है जो इंटरफ़ेस को लागू करने वाली कक्षाओं में तुलना करने की अनुमति देने के लिए अनुबंध को बराबर करता है। सेट, सूची, मानचित्र और Map.Entry जैसे संग्रह इंटरफ़ेस में यह गुण होता है।

  3. तर्क को सही प्रकार से लिखें। क्योंकि इस कास्ट को एक इंस्टॉफ टेस्ट से पहले लिया गया था, इसलिए इसे सफल होने की गारंटी है।

  4. कक्षा में प्रत्येक "महत्वपूर्ण" फ़ील्ड के लिए, जांच लें कि क्या तर्क का वह क्षेत्र इस ऑब्जेक्ट के संबंधित फ़ील्ड से मेल खाता है। यदि ये सभी परीक्षण सफल होते हैं, तो सही लौटें; अन्यथा, झूठे लौटें। यदि चरण 2 में प्रकार एक इंटरफ़ेस है, तो आपको तर्क के क्षेत्रों को इंटरफ़ेस विधियों के माध्यम से एक्सेस करना होगा; यदि प्रकार एक वर्ग है, तो आप उनकी पहुँच के आधार पर सीधे खेतों तक पहुँचने में सक्षम हो सकते हैं।

  5. उन आदिम क्षेत्रों के लिए जिनका प्रकार floatया नहीं है double, ==तुलना के लिए ऑपरेटर का उपयोग करें ; ऑब्जेक्ट संदर्भ फ़ील्ड के लिए, equalsविधि को पुनरावर्ती रूप से कॉल करें ; के लिए floatखेतों, स्थिर का उपयोग Float.compare(float, float)विधि; और के लिए doubleखेतों, का उपयोग Double.compare(double, double)। फ्लोट और डबल फ़ील्ड्स का विशेष उपचार आवश्यक रूप से Float.NaN, -0.0fऔर अनुरूप दोहरे मूल्यों के अस्तित्व द्वारा किया जाता है ; आप तुलना कर सकते हैं जबकि floatऔर doubleस्थिर तरीकों के साथ खेतों Float.equalsऔर Double.equals, इस हर तुलना है, जो खराब प्रदर्शन के लिए होता है पर autoboxing करना पड़ेगा। के लिए arrayखेतों, प्रत्येक तत्व के लिए इन दिशानिर्देशों को लागू करें। यदि किसी सरणी फ़ील्ड में प्रत्येक तत्व महत्वपूर्ण है, तो किसी एक Arrays.equalsविधि का उपयोग करें ।

  6. कुछ ऑब्जेक्ट संदर्भ फ़ील्ड में वैध रूप से शामिल हो सकते हैं null। की संभावना से बचने के NullPointerExceptionलिए, स्थैतिक विधि का उपयोग करके समानता के लिए ऐसे क्षेत्रों की जांच करें Objects.equals(Object, Object)

    // Class with a typical equals method
    
    public final class PhoneNumber {
    
        private final short areaCode, prefix, lineNum;
    
        public PhoneNumber(int areaCode, int prefix, int lineNum) {
    
            this.areaCode = rangeCheck(areaCode,  999, "area code");
    
            this.prefix   = rangeCheck(prefix,    999, "prefix");
    
            this.lineNum  = rangeCheck(lineNum,  9999, "line num");
    
        }
    
        private static short rangeCheck(int val, int max, String arg) {
    
            if (val < 0 || val > max)
    
               throw new IllegalArgumentException(arg + ": " + val);
    
            return (short) val;
    
        }
    
        @Override public boolean equals(Object o) {
            if (o == this)
                return true;
            if (!(o instanceof PhoneNumber))
                return false;
            PhoneNumber pn = (PhoneNumber)o;
            return pn.lineNum == lineNum && pn.prefix == prefix
                    && pn.areaCode == areaCode;
        }
        ... // Remainder omitted
    
    }

1
यह बताना न भूलें कि आपको ओवरराइड hashCode()भी करना है। यह भी ध्यान दें, कि चूंकि Java7 लेखन equals()और hashCode()विधियों का उपयोग करके Objects.equals(), Arrays.equals()और Objects.hashCode(), और बहुत आसान हो गया है Arrays.hashCode()
अर्नोल्ड स्क्रीवर

3
Instof if (getClass() != obj.getClass()) ...ऑपरेटर का उपयोग करने के बजाय उपयोग करने पर विचार करें । इसके लिए उप-प्रकार मैच के बजाय सटीक प्रकार के मिलान की आवश्यकता होगी । - सममित आवश्यकता।
योयो

@ योयो सही है ... उदाहरण के उपयोग से सममित संपत्ति विफल हो सकती है। यदि ओ PhoneNumber का उपवर्ग है जैसे शायद PhoneNumberWithExtension, और यह उसी तरह से ओवरराइड करता है जैसे कि Instof का उपयोग करके, तो o.equals (यह) Instof परीक्षण में विफल हो जाएगा, जबकि PhoneNumber। असेंबल इसे पास कर देगा और सही लौटेगा (अन्य सभी PhoneNumber फ़ील्ड मानकर) बराबर हैं)।
ldkronos

5

चूंकि मैं अनुमान लगा रहा हूं कि ageयह टाइप का है int:

public boolean equals(Object other){
    boolean result;
    if((other == null) || (getClass() != other.getClass())){
        result = false;
    } // end if
    else{
        People otherPeople = (People)other;
        result = name.equals(otherPeople.name) &&  age == otherPeople.age;
    } // end else

    return result;
} // end equals

यह एक में परिणाम होगा NullPointerExceptionअगर nameहै null
orien

@ नोरियन कोई बड़ी बात नहीं है, शायद यह उस अनुबंध में है जिसे nameकभी भी कोई nullमूल्य नहीं मिलता है ...
फोरट्रान

@fortran तो ... शायद यह एक बड़ी बात नहीं है;)
उन्मुखी

5

जावा में वस्तुओं की तुलना करते समय, आप एक शब्दार्थ जाँच करते हैं , वस्तुओं के प्रकार और पहचान की स्थिति की तुलना :

  • खुद (एक ही उदाहरण)
  • स्वयं (क्लोन, या पुनर्निर्मित प्रतिलिपि)
  • विभिन्न प्रकार की अन्य वस्तुएं
  • उसी प्रकार की अन्य वस्तुएं
  • null

नियम:

  • समरूपता :a.equals(b) == b.equals(a)
  • equals()हमेशा पैदावार trueया false, लेकिन कभी नहीं NullpointerException, ClassCastExceptionया किसी भी अन्य फेंकने योग्य है

तुलना:

  • प्रकार की जांच : दोनों उदाहरणों को एक ही प्रकार का होना चाहिए , जिसका अर्थ है कि आपको समानता के लिए वास्तविक वर्गों की तुलना करनी होगी। यह अक्सर सही तरीके से लागू नहीं किया जाता है, जब डेवलपर्स instanceofप्रकार की तुलना के लिए उपयोग करते हैं (जो केवल तब तक काम करता है जब तक कोई उपवर्ग नहीं होता है, और जब सममिति नियम का उल्लंघन होता है A extends B -> a instanceof b != b instanceof a)
  • पहचान करने वाले राज्य की शब्दार्थ जाँच : सुनिश्चित करें कि आप समझते हैं कि किस राज्य द्वारा उदाहरणों की पहचान की गई है। व्यक्तियों की पहचान उनके सामाजिक सुरक्षा नंबर से की जा सकती है, लेकिन बालों के रंग (रंगे हुए), नाम (बदला जा सकता है) या उम्र (हर समय बदलाव) से नहीं। केवल मूल्य वस्तुओं के साथ आपको पूर्ण राज्य (सभी गैर-क्षणिक क्षेत्र) की तुलना करनी चाहिए, अन्यथा केवल वही जांचें जो उदाहरण की पहचान करता है।

आपकी Personकक्षा के लिए:

public boolean equals(Object obj) {

    // same instance
    if (obj == this) {
        return true;
    }
    // null
    if (obj == null) {
        return false;
    }
    // type
    if (!getClass().equals(obj.getClass())) {
        return false;
    }
    // cast and compare state
    Person other = (Person) obj;
    return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}

पुन: प्रयोज्य, सामान्य उपयोगिता वर्ग:

public final class Equals {

    private Equals() {
        // private constructor, no instances allowed
    }

    /**
     * Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
     *
     * @param instance       object instance (where the equals() is implemented)
     * @param other          other instance to compare to
     * @param stateAccessors stateAccessors for state to compare, optional
     * @param <T>            instance type
     * @return true when equals, false otherwise
     */
    public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
        if (instance == null) {
            return other == null;
        }
        if (instance == other) {
            return true;
        }
        if (other == null) {
            return false;
        }
        if (!instance.getClass().equals(other.getClass())) {
            return false;
        }
        if (stateAccessors == null) {
            return true;
        }
        return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
    }
}

आपकी Personकक्षा के लिए, इस उपयोगिता वर्ग का उपयोग करते हुए:

public boolean equals(Object obj) {
    return Equals.as(this, obj, t -> t.name, t -> t.age);
}

1

यदि आयु int है तो आपको == का उपयोग करना चाहिए यदि यह Integer ऑब्जेक्ट है तो आप बराबर () का उपयोग कर सकते हैं। यदि आप समतुल्य को ओवरराइड करते हैं तो आपको हैशकोड पद्धति को भी लागू करना होगा। अनुबंध का विवरण ऑब्जेक्ट के javadoc में और वेब के विभिन्न पृष्ठों पर भी उपलब्ध है।


0

यहाँ समाधान है जो मैंने हाल ही में उपयोग किया है:

public class Test {
    public String a;
    public long b;
    public Date c;
    public String d;
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Test)) {
            return false;
        }
        Test testOther = (Test) obj;
        return (a != null ? a.equals(testOther.a) : testOther.a == null)
                && (b == testOther.b)
                && (c != null ? c.equals(testOther.c) : testOther.c == null)
                && (d != null ? d.equals(testOther.d) : testOther.d == null);
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.