2009-10-27 22 views
19

मैं पैरामीटर श्रेणी के लिए equals विधि को ओवरराइड करने का प्रयास कर रहा हूं।ओवरराइडिंग "बराबर" विधि: पैरामीटर के प्रकार को कैसे समझें?

@Override 
public boolean equals(Object obj) { 
    if (this == obj) 
     return true; 
    if (obj == null) 
     return false; 
    if (!(obj instanceof Tuple)) 
     return false; 

    Tuple<E> other = (Tuple<E>) obj; //unchecked cast 
    if (!a0.equals(other.a0) && !a0.equals(other.a1)) { 
     return false; 
    } 
    if (!a1.equals(other.a1) && !a1.equals(other.a0)) { 
     return false; 
    } 

    return true; 
} 

मैं कैसे सुनिश्चित करें कि other वस्तु की <E>this रूप में ही है बना सकते हैं?

+2

बीटीडब्ल्यू इस तर्क का अर्थ यह नहीं है कि "ए", "ए" और "ए", "बी" बराबर हैं? क्या यह लिखना आसान नहीं होगा "अगर a0 = a0 और a1 = a1, या a0 = a1 और a1 = a0 ..." –

+0

यदि आप अपने a0 और a1 को शून्य होने की अनुमति देते हैं, तो सुनिश्चित करें कि आप चेक जोड़ते हैं इसके लिए। –

उत्तर

15

आप Class<E> प्रकार के लिए एक संदर्भ को बनाए रखना द्वारा यह कर सकते हैं। हालांकि, मेरी राय में, समानता परीक्षण मूल्यों वस्तुओं बल्कि ठोस प्रकार के मूल्यों व्यक्त की तुलना में प्रतिनिधित्व के बारे में होना चाहिए।

इस का एक उत्कृष्ट उदाहरण उदाहरण के लिए संग्रह एपीआई है। new ArrayList<String>().equals(new LinkedList<Object>())true देता है। हालांकि इनके पास पूरी तरह से अलग प्रकार हैं, वे एक ही मूल्य का प्रतिनिधित्व करते हैं, अर्थात् "एक खाली संग्रह"।

व्यक्तिगत रूप से, चाहिए दो Tuple रों है कि एक ही डेटा (जैसे ("a", "b")) जैसी नहीं हो प्रतिनिधित्व करते हैं, क्योंकि एक प्रकार Tuple<String> जबकि अन्य Tuple<Object> है की है?

+0

बिल्कुल ... इस मामले में कक्षा टोकन संग्रहीत करना व्यर्थ है। –

+5

आईडी और आईडी

के बारे में, भले ही ऑब्जेक्ट (डेटाबेस आईडी) के अंदर वास्तविक मूल्य समान है, मुझे नहीं लगता कि उन्हें अलग-अलग डीबी कॉलम के लिए आईडी का प्रतिनिधित्व करने के बराबर माना जाना चाहिए। स्पष्ट स्पष्टीकरण के लिए – herman

+1

+1, लेकिन मैं यहां भी शामिल करूंगा कि समकक्ष विधि में क्या लिखना है जब संकलक चेतावनी को हटाने के लिए पैरामीटर प्रकार महत्वपूर्ण नहीं है। अन्य इसे पढ़ने के लिए, इस पृष्ठ पर एक और जवाब है जो वाइल्डकार्ड का उल्लेख करता है और इसका उपयोग यहां किया जाता है। – C0M37

4

मिटाने के कारण आप नहीं कर सकते हैं। सबसे अच्छा आप कर सकते हैं टुपल क्लास में स्टोर जिसे आप टुपल के लिए "java.lang.Class" फ़ील्ड सदस्य में रखने के लिए योजना बनाते हैं। फिर आप यह सुनिश्चित करने के लिए उन क्षेत्रों की तुलना कर सकते हैं कि ट्यूपल क्लास एक ही प्रकार का हो रहा है।

इसके अलावा इस सूत्र देखें: What is the equivalent of the C++ Pair<L,R> in Java?

अगर आप अपने वर्ग के बारे में अधिक पोस्ट यह मदद मिलेगी। मैं अनचेक कास्ट सोच रहा हूं और आपके बराबर फ़ील्ड की संख्या का मतलब है कि यह ट्यूपल < ई, एफ > नहीं होना चाहिए?

संपादित करें: यहां एक उपयोगी जोड़ी कक्षा है जो मैं नियमित रूप से उपयोग करता हूं (यदि आवश्यक हो तो आप अपने ट्यूपल क्लास को अनुकूलित कर सकते हैं)। नोट, इस वर्ग के अन्य लोगों द्वारा सुझावों के समान, बस निहित सदस्यों को समानता के प्रश्न का निर्णय लेने देता है। आपका उपयोग मामला यह निर्धारित करना चाहिए कि समानता वास्तव में निहित सदस्यों के प्रकार पर आधारित है या नहीं।

/** 
* Adapted from http://forums.sun.com/thread.jspa?threadID=5132045 
* 
* 
* @author Tim Harsch 
* 
* @param <L> 
* @param <R> 
*/ 
public class Pair<L, R> { 

    private final L left; 
    private final R right; 

    public R getRight() { 
     return right; 
    } // end getter 

    public L getLeft() { 
     return left; 
    } // end getter 

    public Pair(final L left, final R right) { 
     this.left = left; 
     this.right = right; 
    } // end constructor 

    public static <A, B> Pair<A, B> create(A left, B right) { 
     return new Pair<A, B>(left, right); 
    } // end factory method 

    @Override 
    public final boolean equals(Object o) { 
     if (!(o instanceof Pair<?,?>)) 
      return false; 

     final Pair<?, ?> other = (Pair<?, ?>) o; 
     return equal(getLeft(), other.getLeft()) && equal(getRight(), other.getRight()); 
    } // end method 

    public static final boolean equal(Object o1, Object o2) { 
     if (o1 == null) { 
      return o2 == null; 
     } 
     return o1.equals(o2); 
    } // end method 

    @Override 
    public int hashCode() { 
     int hLeft = getLeft() == null ? 0 : getLeft().hashCode(); 
     int hRight = getRight() == null ? 0 : getRight().hashCode(); 

     return hLeft + (37 * hRight); 
    } // end method 

    @Override 
    public String toString() { 
     StringBuilder sb = new StringBuilder(); 
     sb.append('<'); 
     if(left == null) { 
      sb.append("null"); 
     } else { 
      sb.append(left.toString()); 
     } // end if 
     sb.append(','); 
     if(right == null) { 
      sb.append("null"); 
     } else { 
      sb.append(right.toString()); 
     } // end if 
     sb.append('>'); 
     return sb.toString(); 
    } // end method 
} // end class 
3

generics are erased at compile time के बाद से, आप मूल रूप से नहीं कर सकते हैं। रनटाइम पर, किसी भी प्रकार का पैरामीटर चला गया है, और जहां तक ​​JVM का संबंध है, वे बिल्कुल सभी मामलों में समान हैं।

तरीका है कि आस-पास काम करने के लिए एक Class क्षेत्र है कि प्रकार का प्रतिनिधित्व करता है की दुकान है, और निर्माता में उस प्रकार के साथ वस्तु बनाने के लिए है।

एक नमूना निर्माता:

public class Tuple <E> { 

    public Tuple(Class<E> c) { 
     //store the class 
    } 

} 

या आप एक कारखाने इस्तेमाल कर सकते हैं: दुर्भाग्य से

public static <E> Tuple <E> getTuple(Class<E> type) { 
    // Create and return the tuple, 
    // just store that type variable in it 
    // for future use in equals. 
} 
3

, आप संकलन समय पर ऐसा नहीं कर सकते; जानकारी चली गई है। type erasure के परिणाम हैं। पैरामीटर को Class इंस्टेंस के रूप में संग्रहीत करने का विकल्प है, और उसके बाद इसे बाद में देखें।

2

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

यह आमतौर पर सच नहीं है कि Foo<Bar> और Foo<Baz> असमान होना चाहिए। तो आपको E की आवश्यकता नहीं है। और, आपके द्वारा लिखे गए कोड में, आपको इसे संकलित करने की भी आवश्यकता नहीं है। बस Tuple<?> पर डालें, क्योंकि वास्तव में आप उस बिंदु पर Tuple के बारे में जानते हैं। यह अभी भी संकलित और सब कुछ।

आप दो बेतहाशा विभिन्न प्रकार के डेटा के साथ पारित कर रहे हैं, तो Tuple है, उन तत्वों equals नहीं होगा, और के रूप में वांछित अपने विधि false वापस आ जाएगी। (एक आशा - equals को लागू करने वाले उन प्रकारों पर निर्भर करता है।)

+0

मुझे नहीं लगता कि ई के प्रकार के संदर्भ को कैसे बनाए रखना स्मृति को लेना; प्रत्येक 'क्लास' ऑब्जेक्ट को क्लासलोडर/जेवीएम द्वारा वैसे भी बनाए रखा जाना चाहिए, इसलिए एकमात्र अतिरिक्त मेमोरी जिसका उपयोग आप करेंगे, पॉइंटर के लिए अतिरिक्त चार बाइट्स (64-बिट सिस्टम के लिए 8) के बारे में है। –

+0

यह सही है, यह संदर्भ है जो अंतरिक्ष लेता है। प्रति ऑब्जेक्ट 4/8 बाइट्स कितने उदाहरण हैं, इस पर निर्भर करता है कि कितने उदाहरण हैं। चूंकि यह समस्या को हल करने में मदद नहीं करता है, ऐसा लगता है, मैं उन संदर्भों को किसी भी आकार में अपमानजनक कहूंगा। –

0

ऑफ-विषय - क्या आपको पता है कि आपके कार्यान्वयन के अनुसार, ट्यूपल (ए0, ए 1) टुपल (ए 1, ए 1) के बराबर है? मुझे लगता है कि नहीं है कि आप क्या चाहते ...

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

वस्तु समानता, और सामान्य पैरामीटर सह/विपरीत विचरण, दो ओर्थोगोनल चिंताएं हैं।

0

मैं सहमत ऊपर टिप्पणी, क्यों वर्ग ई बराबर होने की जरूरत है? और आप ई के उप-वर्गों का इलाज कैसे करना चाहते हैं?

वैसे भी, यह देखते हुए कि यहाँ एक कोड नमूना आप मदद कर सकते हैं है:

public class Example<T> { 

    T t; 

    public Example(T t) { 
    this.t = t; 
    } 

    public static void main(String[] args) { 
    final String s = "string"; 
    final Integer i = 1; 
    final Number n = 1; 

    final Example<String> exampleString = new Example<String>(s); 
    final Example<Integer> exampleInteger = new Example<Integer>(i); 
    final Example<Number> exampleNumber = new Example<Number>(n); 

    System.out.println("exampleString subclass " + exampleString.t.getClass()); 
    System.out.println("exmapleIntger subclass " + exampleInteger.t.getClass()); 
    System.out.println("exmapleNumber subclass " + exampleNumber.t.getClass()); 
    System.out.println("Integer equals Number = " + 
     exampleInteger.t.equals(exampleNumber.t)); 
    } 
} 

आप t.getClass कॉल कर सकते हैं() टी के प्रकार के बारे कक्षा की जानकारी प्राप्त करने के लिए (यह मानते हुए इसके बारे में, अशक्त नहीं है पाठ्यक्रम।)

मुझे उम्मीद है कि इससे मदद मिलती है।

4

मैं सिर्फ अपने आप को इस समस्या का सामना किया, और मेरे -particular- मामले में, मैं प्रकार ई

उदाहरण के लिए पता करने की जरूरत नहीं किया:

public class Example<E> { 
    E value; 

    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     Example<?> other = (Example<?>) obj; 
     if (value == null) { 
      if (other.value != null) 
       return false; 
     } else if (!value.equals(other.value)) 
      return false; 
     return true; 
    } 
} 

उपरोक्त कोड में, Example<?> का उपयोग करने के कारण कोई अनचेक कास्ट नहीं है। टाइप पैरामीटर वाइल्डकार्ड '?' दिन बचाता है

+1

इस तरह के का उपयोग करने के लिए कभी सोचा नहीं। यह एक शानदार जवाब है, क्योंकि ज्यादातर समय, पैरामीटरेटेड क्लास में बराबर जांच के दौरान, वास्तव में कोई भी परवाह नहीं करना चाहिए कि जेनेरिक किस प्रकार हैं। +1 – C0M37

+0

1. सवाल यह था कि टाइप पैरामीटर बराबर कैसे हैं, और यह उत्तर केवल "असुरक्षित कास्ट" चेतावनी से बचाता है जबकि टाइप पैरामीटर की जांच नहीं की जाती है -> डाउनवॉटेड 2. वास्तव में ऐसे मामले हैं जहां आप चाहते हैं विभिन्न प्रकार के उदाहरणों को असमान माना जाता है – herman

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