क्या दो वस्तुओं की गहरी तुलना करने के लिए जावा परावर्तन उपयोगिता है?


99

मैं clone()एक बड़े प्रोजेक्ट के अंदर कई तरह के ऑपरेशन के लिए यूनिट टेस्ट लिखने की कोशिश कर रहा हूं और सोच रहा हूं कि क्या कोई मौजूदा वर्ग कहीं ऐसा है जो एक ही तरह की दो वस्तुओं को लेने में सक्षम है, एक गहरी तुलना कर रहा है, और कह रहा है कि क्या वे 'समान हैं या नहीं?


1
इस वर्ग को कैसे पता चलेगा कि वस्तु ग्राफ के एक निश्चित बिंदु पर वह समान वस्तुओं को स्वीकार कर सकता है, या केवल उसी संदर्भ को?
जेड

आदर्श रूप से यह पर्याप्त रूप से कॉन्फ़िगर किया जा सकता है :) मैं कुछ स्वचालित की तलाश कर रहा हूं ताकि यदि नए फ़ील्ड जोड़े जाएं (और क्लोन नहीं किए गए) तो परीक्षण उन्हें पहचान सकता है।
उड़ी

3
जो मैं कहना चाह रहा हूं वह यह है कि आपको तुलनाओं को वैसे भी कॉन्फ़िगर (लागू) करना होगा। तो फिर क्यों नहीं अपनी कक्षाओं में समान पद्धति को ओवरराइड करें और इसका उपयोग करें?
जेड

3
यदि बड़ी जटिल वस्तु के लिए समान रिटर्न गलत है, तो आप कहां से शुरू करते हैं? आप एक बहु-पंक्ति स्ट्रिंग में ऑब्जेक्ट को चालू करने और स्ट्रिंग तुलना करने से बहुत बेहतर हैं। तब आप ठीक-ठीक देख सकते हैं कि दो वस्तुएं कहां भिन्न हैं। IntelliJ एक "परिवर्तन" तुलना विंडो को पॉप अप करता है जो दो परिणामों के बीच कई बदलाव खोजने में मदद करता है अर्थात यह assertEquals (string1, string2) के आउटपुट को समझता है और आपको एक तुलना विंडो देता है।
बजे पीटर लॉरी

यहाँ कुछ बहुत अच्छे जवाब हैं, स्वीकृत एक के अलावा, जो दफन हो गए हैं
user1445967

जवाबों:


63

यूनिट्स की यह कार्यक्षमता है:

जावा डिफ़ॉल्ट / अशक्त मूल्यों की अनदेखी और संग्रह के आदेश की अनदेखी जैसे विभिन्न विकल्पों के साथ प्रतिबिंब के माध्यम से समानता


9
मैंने इस फ़ंक्शन पर कुछ परीक्षण किए हैं और यह एक गहरी तुलना करने के लिए लगता है जहां इक्वाल्सबर्ल नहीं करता है।
हावर्ड मई

वहाँ एक तरीका यह क्षणिक क्षेत्रों की अनदेखी नहीं है?
पिंच

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

@ वोल्फगैंग क्या हमें निर्देशित करने के लिए कोई नमूना कोड है? आपने वह बोली कहाँ से खींची?
अनोन 58192932

30

मुझे यह सवाल पसंद है! मुख्य रूप से क्योंकि यह शायद ही कभी जवाब दिया या बुरी तरह से जवाब दिया है। यह ऐसा है जैसे किसी ने अभी तक इसका पता नहीं लगाया है। वर्जिन क्षेत्र :)

सबसे पहले, का उपयोग करने के बारे में भी मत सोचोequals । के अनुबंध equals, के रूप में जावाडोक में परिभाषित किया गया है, एक तुल्यता संबंध (कर्मकर्त्ता, सममित, और सकर्मक), है एक समानता संबंध। उसके लिए, यह एंटीसिममेट्रिक भी होना चाहिए। इसका एकमात्र कार्यान्वयन equals(या कभी भी हो सकता है) एक सच्चे समानता का संबंध है java.lang.Object। भले ही आपने equalsग्राफ़ की हर चीज़ की तुलना करने के लिए उपयोग किया हो , लेकिन अनुबंध तोड़ने का जोखिम काफी अधिक है। जैसा कि जोश बलोच ने प्रभावी जावा में बताया , बराबरी का अनुबंध तोड़ना बहुत आसान है:

"बराबरी के अनुबंध को संरक्षित करते हुए एक तात्कालिक वर्ग का विस्तार करने और एक पहलू को जोड़ने का कोई तरीका नहीं है"

इसके अलावा क्या एक बूलियन विधि वास्तव में आप वैसे भी है? यह वास्तव में मूल और क्लोन के बीच के सभी अंतरों को अलग करना अच्छा होगा, क्या आपको नहीं लगता है? इसके अलावा, मैं यहाँ यह मानूंगा कि आप ग्राफ़ में प्रत्येक ऑब्जेक्ट के लिए तुलना कोड लिखने / बनाए रखने से परेशान नहीं होना चाहते हैं, बल्कि आप कुछ ऐसी चीज़ की तलाश कर रहे हैं जो स्रोत के साथ स्केल हो जाए क्योंकि यह समय के साथ बदलता रहता है।

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

कुछ मुद्दों पर आप का सामना करेंगे:

  • संग्रह क्रम: क्या दो संग्रह समान माने जाने चाहिए यदि वे एक ही वस्तु को धारण करते हैं, लेकिन एक अलग क्रम में?
  • किन क्षेत्रों की अनदेखी: क्षणिक? स्टेटिक?
  • प्रकार तुल्यता: क्या फील्ड मान बिल्कुल एक ही प्रकार के होने चाहिए? या एक का विस्तार दूसरे के लिए करना ठीक है?
  • वहाँ अधिक है, लेकिन मैं भूल गया ...

XStream बहुत तेज़ है और XMLUnit के साथ मिलकर कोड की कुछ लाइनों में काम करेगा। XMLUnit अच्छा है क्योंकि यह सभी मतभेदों की रिपोर्ट कर सकता है, या बस पहले एक को रोक सकता है जो इसे पाता है। और इसके आउटपुट में अलग-अलग नोड्स के लिए xpath शामिल है, जो अच्छा है। डिफ़ॉल्ट रूप से यह अनियोजित संग्रह की अनुमति नहीं देता है, लेकिन ऐसा करने के लिए इसे कॉन्फ़िगर किया जा सकता है। विशेष अंतर हैंडलर इंजेक्ट करना (जिसे कॉल किया जाता है DifferenceListener) आपको अनदेखा करने के आदेश सहित अंतर से निपटने के तरीके को निर्दिष्ट करने की अनुमति देता है। हालाँकि, जैसे ही आप सरलतम अनुकूलन से परे कुछ भी करना चाहते हैं, लिखना मुश्किल हो जाता है और विवरण एक विशिष्ट डोमेन ऑब्जेक्ट से बंध जाते हैं।

मेरी व्यक्तिगत प्राथमिकता सभी घोषित क्षेत्रों के माध्यम से प्रतिबिंब का उपयोग करना और हर एक में नीचे ड्रिल करना है, जैसे कि मैं जाता हूं, अंतर को ट्रैक करना। चेतावनी का शब्द: जब तक आप स्टैक ओवरफ़्लो अपवाद पसंद नहीं करते हैं, तब तक पुनरावृत्ति का उपयोग न करें। स्टैक के साथ चीजों को दायरे में रखें (a का उपयोग करेंLinkedListया कुछ और)। मैं आमतौर पर क्षणिक और स्थिर क्षेत्रों को अनदेखा करता हूं, और मैं उन ऑब्जेक्ट जोड़े को छोड़ देता हूं, जिनकी मैंने पहले से ही तुलना की है, इसलिए मैं अनंत छोरों में अंत नहीं करता हूं अगर किसी ने स्व-संदर्भ कोड लिखने का फैसला किया (हालांकि, मैं हमेशा आदिम आवरणों की तुलना करता हूं कोई फर्क नहीं पड़ता कि क्या , क्योंकि एक ही वस्तु refs अक्सर पुन: उपयोग किया जाता है)। आप संग्रह ऑर्डर को अनदेखा करने के लिए और विशेष प्रकार या फ़ील्ड को अनदेखा करने के लिए सामने की चीज़ों को कॉन्फ़िगर कर सकते हैं, लेकिन मुझे एनोटेशन के माध्यम से फ़ील्ड पर अपनी राज्य तुलना नीतियों को परिभाषित करना पसंद है। यह, IMHO, वास्तव में एनोटेशन के लिए था, जो रनटाइम पर उपलब्ध क्लास के बारे में मेटा डेटा बनाने के लिए था। कुछ इस तरह:


@StatePolicy(unordered=true, ignore=false, exactTypesOnly=true)
private List<StringyThing> _mylist;

मुझे लगता है कि यह वास्तव में एक कठिन समस्या है, लेकिन पूरी तरह से हल करने योग्य है! और एक बार आपके पास कुछ है जो आपके लिए काम करता है, यह वास्तव में है, वास्तव में, उपयोगी है :)

इतनी अच्छी किस्मत। और अगर आप कुछ ऐसा कर रहे हैं, जो सिर्फ शुद्ध प्रतिभा है, तो शेयर करना न भूलें!


15

दीपावली और दीपशकोड देखें () जावा-उपयोग के भीतर: https://github.com/jdereg/java/util

यह वर्ग वही करता है जो मूल लेखक अनुरोध करता है।


4
चेतावनी: यदि कोई मौजूद है, तो डीपक्वाल्स किसी वस्तु के .equals () पद्धति का उपयोग करता है। यह वह नहीं हो सकता जो आप चाहते हैं।
आदम

4
यह एक वर्ग पर केवल .equals () का उपयोग करता है यदि एक बराबरी () विधि को स्पष्ट रूप से जोड़ा गया है, अन्यथा यह सदस्य-दर-सदस्य तुलना करता है। यहाँ तर्क यह है कि यदि कोई कस्टम बराबरी () विधि लिखने के प्रयास में गया है तो इसका उपयोग किया जाना चाहिए। भविष्य में वृद्धि: ध्वज को अनुमति देता है कि भले ही यह मौजूद हो (फिर भी) समान तरीकों की अनदेखी करें। जावा-उपयोग में उपयोगी उपयोगिताएँ हैं, जैसे CaseInsensitiveMap / Set।
जॉन डीरेगोनकोर्ट

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

ऊपर @beluchin का उत्तर देने के लिए, DeepEquals.deepEquals () हमेशा फ़ील्ड-दर-फ़ील्ड तुलना नहीं करता है। सबसे पहले, यह एक विधि पर .equals () का उपयोग करने का विकल्प है यदि कोई मौजूद है (जो ऑब्जेक्ट पर एक नहीं है), या इसे अनदेखा किया जा सकता है। दूसरा, मैप्स / कलेक्शंस की तुलना करते समय, यह कलेक्शन या मैप टाइप को नहीं देखता है, न ही कलेक्शन / मैप पर फील्ड्स को। इसके बजाय, यह उनकी तार्किक रूप से तुलना करता है। एक LinkedHashMap एक TreeMap के बराबर हो सकता है यदि उनके पास समान क्रम में समान सामग्री और तत्व हैं। गैर-ऑर्डर किए गए संग्रह और मानचित्रों के लिए, केवल आकार और गहरी-समान वस्तुओं की आवश्यकता होती है।
बजे जॉन डीरेगोनकोर्ट

मैप्स / कलेक्शंस की तुलना करते समय, यह कलेक्शन या मैप टाइप को नहीं देखता है, न ही कलेक्शन / मैप पर फ़ील्ड्स को। इसके बजाय, यह उनकी तार्किक रूप से @JohnDeRegnaucourt से तुलना करता है , मैं इस तार्किक तुलना का तर्क दूंगा अर्थात् केवल publicसंग्रह / मानचित्र पर लागू होने के विपरीत सभी प्रकारों पर लागू होने वाली चीज़ों की तुलना करना चाहिए।
बेलुचिन

10

बराबरी ओवरराइड () विधि

आप यहाँ बताए अनुसार EqualsBuilder.reflectionEquals () का उपयोग करके वर्ग के बराबर () विधि को ओवरराइड कर सकते हैं :

 public boolean equals(Object obj) {
   return EqualsBuilder.reflectionEquals(this, obj);
 }

7

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

https://github.com/SQiShER/java-object-diff

आप एक ही प्रकार की दो वस्तुओं की तुलना कर सकते हैं और यह परिवर्तन, परिवर्धन और निष्कासन दिखाएगा। यदि कोई परिवर्तन नहीं हैं, तो ऑब्जेक्ट समान हैं (सिद्धांत रूप में)। चेक के दौरान प्राप्तकर्ताओं को नजरअंदाज किया जाता है। फ्रेम वर्क में समता जाँच की तुलना में कहीं अधिक व्यापक अनुप्रयोग हैं, अर्थात मैं एक परिवर्तन-लॉग उत्पन्न करने के लिए उपयोग कर रहा हूँ।

इसका प्रदर्शन ठीक है, जेपीए संस्थाओं की तुलना करते समय, पहले उन्हें इकाई प्रबंधक से अलग करना सुनिश्चित करें।


6

मैं हूँ XStream:

/**
 * @see java.lang.Object#equals(java.lang.Object)
 */
@Override
public boolean equals(Object o) {
    XStream xstream = new XStream();
    String oxml = xstream.toXML(o);
    String myxml = xstream.toXML(this);

    return myxml.equals(oxml);
}

/**
 * @see java.lang.Object#hashCode()
 */
@Override
public int hashCode() {
    XStream xstream = new XStream();
    String myxml = xstream.toXML(this);
    return myxml.hashCode();
}

5
सूचियों की तुलना में अन्य संग्रह में अलग-अलग क्रम में तत्व वापस आ सकते हैं, इसलिए स्ट्रिंग तुलना विफल हो जाएगी।
एलेक्सी बेरेकिन

इसके अलावा, जो धारावाहिक नहीं हैं, वे विफल होंगे
Zwelch

6

में AssertJ , आप कर सकते हैं:

Assertions.assertThat(expectedObject).isEqualToComparingFieldByFieldRecursively(actualObject);

संभवतः यह सभी मामलों में काम नहीं करेगा, हालाँकि यह अधिक मामलों में काम करेगा जो आप सोचेंगे।

यहाँ प्रलेखन क्या कहता है:

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

पुनरावर्ती तुलना चक्र को संभालती है। डिफ़ॉल्ट रूप से झंडे की तुलना 1.0E-6 की सटीकता और 1.0E-15 के साथ युगल से की जाती है।

आप प्रति कस्टमाइज़र (नेस्टेड) ​​फ़ील्ड्स को निर्दिष्ट कर सकते हैं या क्रमशःComparatorForFields (Comparator, String ...) का उपयोग करके औरComparatorForType (Comparator, Class) का उपयोग करके टाइप कर सकते हैं।

तुलना करने के लिए वस्तुएं विभिन्न प्रकार की हो सकती हैं लेकिन उनमें समान गुण / क्षेत्र होने चाहिए। उदाहरण के लिए यदि वास्तविक वस्तु का नाम स्ट्रिंग फ़ील्ड है, तो यह अपेक्षित है कि अन्य ऑब्जेक्ट में भी एक हो। यदि किसी ऑब्जेक्ट में एक फ़ील्ड और एक ही नाम वाली प्रॉपर्टी है, तो प्रॉपर्टी वैल्यू का उपयोग फ़ील्ड में किया जाएगा।


1
isEqualToComparingFieldByFieldRecursivelyअब पदावनत हो गया है। assertThat(expectedObject).usingRecursiveComparison().isEqualTo(actualObject);इसके बजाय का उपयोग करें :)
dargmuesli

5

http://www.unitils.org/tutorial-reflectionassert.html

public class User {

    private long id;
    private String first;
    private String last;

    public User(long id, String first, String last) {
        this.id = id;
        this.first = first;
        this.last = last;
    }
}
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);

2
विशेष रूप से उपयोगी अगर आपको उत्पन्न वर्गों को संभालना है, जहां आपके पास बराबरी के बारे में कोई प्रभाव नहीं है!
मथायस बी

1
stackoverflow.com/a/1449051/829755 ने पहले ही इसका उल्लेख किया है। आपको उस पोस्ट को संपादित करना चाहिए
user829755

1
@ user829755 इस तरह मैं अंक खो देता हूं। सभी बिंदु खेल के बारे में))) जैसे लोगों को नौकरी के लिए क्रेडिट मिलता है, मैं भी हूं।
गवेंको

3

हैमरेस्ट में माचिस समान रूप से वेलवेज़ है । लेकिन यह जावाबींस कन्वेंशन पर निर्भर करता है (गेटर्स और सेटर का उपयोग करता है)। क्या जिन वस्तुओं की तुलना की जानी है, उनकी विशेषताओं के लिए गेटर्स और सेटर नहीं हैं, यह काम नहीं करेगा।

import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class UserTest {

    @Test
    public void asfd() {
        User user1 = new User(1, "John", "Doe");
        User user2 = new User(1, "John", "Doe");
        assertThat(user1, samePropertyValuesAs(user2)); // all good

        user2 = new User(1, "John", "Do");
        assertThat(user1, samePropertyValuesAs(user2)); // will fail
    }
}

उपयोगकर्ता बीन - गेटर्स और सेटर के साथ

public class User {

    private long id;
    private String first;
    private String last;

    public User(long id, String first, String last) {
        this.id = id;
        this.first = first;
        this.last = last;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirst() {
        return first;
    }

    public void setFirst(String first) {
        this.first = first;
    }

    public String getLast() {
        return last;
    }

    public void setLast(String last) {
        this.last = last;
    }

}

यह तब तक बहुत अच्छा काम करता है जब तक कि आपके पास एक पीओजेओ नहीं है जो isFooकिसी Booleanसंपत्ति के लिए रीड विधि का उपयोग कर रहा है । इसे ठीक करने के लिए 2016 से खुला एक पीआर है। github.com/hamcrest/Java
Hamcrest

2

यदि आपकी वस्तुएँ सीरियल योग्य हैं तो आप इसका उपयोग कर सकते हैं:

public static boolean deepCompare(Object o1, Object o2) {
    try {
        ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
        ObjectOutputStream oos1 = new ObjectOutputStream(baos1);
        oos1.writeObject(o1);
        oos1.close();

        ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
        ObjectOutputStream oos2 = new ObjectOutputStream(baos2);
        oos2.writeObject(o2);
        oos2.close();

        return Arrays.equals(baos1.toByteArray(), baos2.toByteArray());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

1

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

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

मैंने थोड़ा सा कोड लिखा था, जो Google कोड में सूचीबद्ध एक संपूर्ण ऑब्जेक्ट ग्राफ का पता लगाता है। Json-io (http://code.google.com/p/json-io/) देखें। यह JSON में एक जावा ऑब्जेक्ट ग्राफ को क्रमबद्ध करता है और इससे deserialized है। यह सभी जावा ऑब्जेक्ट्स को सार्वजनिक निर्माणकर्ताओं के साथ या उनके बिना, सीरियलियुजेबल या सीरियलाइज़ेबल के बिना संभालता है। यह वही ट्रैवर्सल कोड बाहरी "बराबर" () "और बाहरी" हैशकोड () "कार्यान्वयन के लिए आधार होगा। Btw, JsonReader / JsonWriter (json-io) आमतौर पर अंतर्निहित ObjectInputStream / ObjectOutputStream की तुलना में तेज़ होता है।

इस JsonReader / JsonWriter का उपयोग तुलना के लिए किया जा सकता है, लेकिन यह हैशकोड के साथ मदद नहीं करेगा। यदि आप एक सार्वभौमिक हैशकोड () और बराबर () चाहते हैं, तो उसे स्वयं कोड की आवश्यकता है। मैं एक सामान्य ग्राफ आगंतुक के साथ इसे खींचने में सक्षम हो सकता हूं। हम देखेंगे।

अन्य विचार - स्थिर क्षेत्र - यह आसान है - उन्हें छोड़ दिया जा सकता है क्योंकि सभी समान () उदाहरणों में स्थिर क्षेत्रों के लिए समान मूल्य होगा, क्योंकि सभी क्षेत्रों में स्थिर क्षेत्रों को साझा किया जाता है।

क्षणिक क्षेत्रों के लिए - यह एक चयन विकल्प होगा। कभी-कभी आप अन्य समय को गिनने के लिए संक्रमण चाह सकते हैं। "कभी-कभी आप अखरोट की तरह महसूस करते हैं, कभी-कभी आप नहीं करते।"

Json-io परियोजना (मेरी अन्य परियोजनाओं के लिए) पर वापस जाएं और आपको बाहरी बराबर () / हैशकोड () परियोजना मिलेगी। मेरे पास अभी तक इसके लिए कोई नाम नहीं है, लेकिन यह स्पष्ट होगा।


1

अपाचे आपको कुछ देता है, दोनों वस्तुओं को स्ट्रिंग में परिवर्तित करें और स्ट्रिंग्स की तुलना करें, लेकिन आपको ओवरराइड करना होगा ()

obj1.toString().equals(obj2.toString())

ओवरराइड स्ट्रिंग ()

यदि सभी क्षेत्र आदिम प्रकार हैं:

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
@Override
public String toString() {return 
ReflectionToStringBuilder.toString(this);}

यदि आपके पास गैर आदिम क्षेत्र और / या संग्रह और / या मानचित्र है:

// Within class
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
@Override
public String toString() {return 
ReflectionToStringBuilder.toString(this,new 
MultipleRecursiveToStringStyle());}

// New class extended from Apache ToStringStyle
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.*;

public class MultipleRecursiveToStringStyle extends ToStringStyle {
private static final int    INFINITE_DEPTH  = -1;

private int                 maxDepth;

private int                 depth;

public MultipleRecursiveToStringStyle() {
    this(INFINITE_DEPTH);
}

public MultipleRecursiveToStringStyle(int maxDepth) {
    setUseShortClassName(true);
    setUseIdentityHashCode(false);

    this.maxDepth = maxDepth;
}

@Override
protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
    if (value.getClass().getName().startsWith("java.lang.")
            || (maxDepth != INFINITE_DEPTH && depth >= maxDepth)) {
        buffer.append(value);
    } else {
        depth++;
        buffer.append(ReflectionToStringBuilder.toString(value, this));
        depth--;
    }
}

@Override
protected void appendDetail(StringBuffer buffer, String fieldName, 
Collection<?> coll) {
    for(Object value: coll){
        if (value.getClass().getName().startsWith("java.lang.")
                || (maxDepth != INFINITE_DEPTH && depth >= maxDepth)) {
            buffer.append(value);
        } else {
            depth++;
            buffer.append(ReflectionToStringBuilder.toString(value, this));
            depth--;
        }
    }
}

@Override
protected void appendDetail(StringBuffer buffer, String fieldName, Map<?, ?> map) {
    for(Map.Entry<?,?> kvEntry: map.entrySet()){
        Object value = kvEntry.getKey();
        if (value.getClass().getName().startsWith("java.lang.")
                || (maxDepth != INFINITE_DEPTH && depth >= maxDepth)) {
            buffer.append(value);
        } else {
            depth++;
            buffer.append(ReflectionToStringBuilder.toString(value, this));
            depth--;
        }
        value = kvEntry.getValue();
        if (value.getClass().getName().startsWith("java.lang.")
                || (maxDepth != INFINITE_DEPTH && depth >= maxDepth)) {
            buffer.append(value);
        } else {
            depth++;
            buffer.append(ReflectionToStringBuilder.toString(value, this));
            depth--;
        }
    }
}}

0

मुझे लगता है कि आप यह जानते हैं, लेकिन सिद्धांत रूप में, आप हमेशा। ओवरल्स को ओवरराइड करने के लिए माना जाता है कि दो ऑब्जेक्ट वास्तव में समान हैं। इसका अर्थ यह होगा कि वे अपने सदस्यों पर अधिक। असमान तरीकों की जाँच करते हैं।

इस तरह की बात यह है। वस्तु में असमानता को क्यों परिभाषित किया गया है।

यदि यह लगातार किया जाता है तो आपको कोई समस्या नहीं होगी।


2
समस्या यह है कि मैं एक बड़े मौजूदा कोडबेस के लिए यह परीक्षण स्वचालित करना चाहता हूं जो मैंने नहीं लिखा था ... :)
उड़ी

0

इस तरह की गहरी तुलना के लिए रुकने की गारंटी एक समस्या हो सकती है। निम्नलिखित को क्या करना चाहिए? (यदि आप इस तरह के तुलनित्र को लागू करते हैं, तो यह एक अच्छी इकाई परीक्षा होगी।)

LinkedListNode a = new LinkedListNode();
a.next = a;
LinkedListNode b = new LinkedListNode();
b.next = b;

System.out.println(DeepCompare(a, b));

यहाँ एक और है:

LinkedListNode c = new LinkedListNode();
LinkedListNode d = new LinkedListNode();
c.next = d;
d.next = c;

System.out.println(DeepCompare(c, d));

यदि आपके पास कोई नया प्रश्न है, तो कृपया प्रश्न पूछें बटन पर क्लिक करके पूछें । इस प्रश्न का लिंक शामिल करें यदि यह संदर्भ प्रदान करने में मदद करता है।
यंगहॉबिट

@younghobbit: नहीं यह कोई नया सवाल नहीं है। एक उत्तर में एक प्रश्न चिह्न उस ध्वज को उपयुक्त नहीं बनाता है। कृपया अधिक ध्यान दें।
बेन वोइगट

इससे: Using an answer instead of a comment to get a longer limit and better formatting.यदि यह एक टिप्पणी है, तो उत्तर अनुभाग का उपयोग क्यों करें? इसीलिए मैंने इसे हरी झंडी दिखाई। के कारण नहीं ?। इस उत्तर को पहले से ही किसी और ने चिह्नित किया है, जिसने टिप्पणी को पीछे नहीं छोड़ा। मुझे यह सिर्फ समीक्षा कतार में मिला। क्या मेरा बुरा हो सकता है, मुझे और अधिक सावधान रहना चाहिए।
यंगहॉबिट

0

मुझे लगता है कि रे हुलहा समाधान से प्रेरित सबसे आसान उपाय वस्तु को क्रमबद्ध करना है और फिर कच्चे परिणाम की तुलना करना है।

क्रमांकन बाइट, json, xml या सरल toString आदि हो सकता है। ToString सस्ता लगता है। लोमोनोक हमारे लिए मुफ्त आसान अनुकूलन योग्य टोट्रिंग उत्पन्न करता है। नीचे उदाहरण देखें।

@ToString @Getter @Setter
class foo{
    boolean foo1;
    String  foo2;        
    public boolean deepCompare(Object other) { //for cohesiveness
        return other != null && this.toString().equals(other.toString());
    }
}   

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