किसी भी कारण से पसंद करते हैं।


174

मैं उत्पन्न करने के लिए ग्रहण का उपयोग कर रहा हूं .equals()और .hashCode(), "प्रकारों की तुलना करने के लिए" उपयोग 'इंस्टोफ़' नामक एक विकल्प है। डिफ़ॉल्ट इस विकल्प के अनियंत्रित होने और .getClass()प्रकारों की तुलना करने के लिए उपयोग करने के लिए है। वहाँ किसी भी कारण से मैं पसंद चाहिए .getClass()से अधिक instanceof?

उपयोग किए बिना instanceof:

if (obj == null)
  return false;
if (getClass() != obj.getClass())
  return false;

का उपयोग कर instanceof:

if (obj == null)
  return false;
if (!(obj instanceof MyClass))
  return false;

मैं आमतौर पर instanceofविकल्प की जांच करता हूं , और फिर अंदर जाकर " if (obj == null)" चेक को हटा देता हूं । (यह निरर्थक है क्योंकि अशक्त वस्तुएं हमेशा विफल रहेंगी instanceof।) क्या कोई कारण है कि एक बुरा विचार है?


1
x instanceof SomeClassअगर xहै तो अभिव्यक्ति झूठी है null। इसलिए, दूसरे सिंटेक्स डोंस को अशक्त जांच की आवश्यकता नहीं है।
रास

5
@ आरडीएस हाँ, कोड स्निपेट के तुरंत बाद का पैराग्राफ भी यही कहता है। यह कोड स्निपेट में है क्योंकि यही ग्रहण उत्पन्न करता है।
किप

जवाबों:


100

यदि आप उपयोग करते हैं instanceof, तो आपका equalsकार्यान्वयन finalविधि के समरूपता अनुबंध को बनाए रखेगा x.equals(y) == y.equals(x):। यदि finalप्रतिबंधात्मक लगता है, तो यह सुनिश्चित करने के लिए कि आपके ओवरराइडिंग कार्यान्वयन पूरी तरह से Objectवर्ग द्वारा स्थापित अनुबंध को बनाए रखते हैं, वस्तु समानता की अपनी धारणा की सावधानीपूर्वक जांच करें ।


ठीक यही बात मेरे दिमाग में आई जब मैंने ऊपर जोश ब्लोच का उद्धरण पढ़ा। +1 :)
जोहान्स स्काउब -

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

मैं यह भी जोड़ता हूं कि "यदि finalप्रतिबंधात्मक लगता है" (दोनों पर ) equalsऔर hashCodeफिर अनुबंध की समरूपता और परिवर्तनशीलता आवश्यकताओं को संरक्षित करने के लिए getClass()समानता का उपयोग करें । instanceofequals
छाया पुरुष

176

जोश बलोच आपके दृष्टिकोण के पक्षधर हैं:

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

इस SO उत्तर को भी देखें ।

प्रभावी जावा अध्याय 3 भी इसे कवर करता है।


18
+1 java करने वाले प्रत्येक व्यक्ति को उस पुस्तक को कम से कम 10 बार पढ़ना चाहिए!
एंड्रे

16
Instof दृष्टिकोण के साथ समस्या यह है कि यह Object.equals () की "सममित" संपत्ति को तोड़ता है, जिसमें यह संभव हो जाता है कि x.equals (y) == सही है लेकिन y.equals (x) == झूठा है अगर x.getassass ()! = y.getClass () मैं इस संपत्ति को तोड़ने के लिए पसंद करता हूं जब तक कि बिल्कुल आवश्यक न हो (यानी, प्रबंधित या छद्म वस्तुओं के लिए बराबरी () से अधिक हो)।
केविन सीटेज़

8
Instof दृष्टिकोण उचित है जब, और केवल तब, जब आधार वर्ग परिभाषित करता है कि उपवर्ग वस्तुओं में क्या समानता होनी चाहिए। का उपयोग करना getClassएलएसपी का उल्लंघन नहीं करता है, क्योंकि एलएसपी का संबंध केवल मौजूदा उदाहरणों से हो सकता है - न कि किस प्रकार के उदाहरणों का निर्माण किया जा सकता है। द्वारा लौटाया गया वर्ग getClassकिसी वस्तु उदाहरण की अपरिवर्तनीय संपत्ति है। एलएसपी का मतलब यह नहीं है कि यह एक उपवर्ग बनाने के लिए संभव होना चाहिए जहां वह संपत्ति किसी भी वर्ग को इंगित करती है जो इसे बनाया गया था।
सुपरकैट

66

एंजेलिका लैंगर्स के राज़ समान हैं, जोश बलोच और बारबरा लिस्कोव सहित कुछ सामान्य और प्रसिद्ध उदाहरणों के लिए एक लंबी और विस्तृत चर्चा के साथ, उनमें से अधिकांश में कुछ समस्याओं की खोज की। वह भी instanceofबनाम में हो जाता है getClass। कुछ बोली इससे

निष्कर्ष

बराबरी के कार्यान्वयन के चार मनमाने ढंग से चुने गए उदाहरणों को विच्छेदित करके (), हम क्या निष्कर्ष निकालते हैं?

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

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

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


61

उपयोग करने का कारण अनुबंध getClassकी सममित संपत्ति सुनिश्चित करना है equals। बराबर से 'JavaDocs:

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

Instof का उपयोग करके, सममित नहीं होना संभव है। उदाहरण पर विचार करें: डॉग पशु का विस्तार करता है। पशु के equalsएक करता है instanceofपशु की जांच। कुत्ते की equalsएक करता है instanceofकुत्ते की जांच। पशु दें एक और कुत्ता (अन्य क्षेत्रों में एक ही साथ):

a.equals(d) --> true
d.equals(a) --> false

यह सममित संपत्ति का उल्लंघन करता है।

समान अनुबंध का सख्ती से पालन करने के लिए, समरूपता सुनिश्चित की जानी चाहिए, और इस तरह वर्ग को समान होना चाहिए।


8
इस सवाल का पहला स्पष्ट और संक्षिप्त जवाब है। एक कोड नमूना एक हजार शब्दों के लायक है।
जॉनराइड

मैं अन्य सभी वर्बोज़ उत्तर उपयोग से गुज़र रहा था जो आपने दिन बचाए थे। संक्षिप्त, संक्षिप्त, सुरुचिपूर्ण और इस प्रश्न का सबसे अच्छा उत्तर।

1
जैसा कि आपने बताया कि समरूपता की आवश्यकता है। लेकिन वहाँ भी "संवेदनशीलता" आवश्यकता है। तो a.equals(c)और b.equals(c), तो a.equals(b)(बनाने का अनुभवहीन दृष्टिकोण Dog.equalsबस return super.equals(object)जब !(object instanceof Dog)लेकिन अतिरिक्त क्षेत्रों की जाँच जब यह एक कुत्ता उदाहरण समरूपता का उल्लंघन नहीं होगा लेकिन संक्रामिता का उल्लंघन होगा)
छाया मैन

सुरक्षित होने के लिए, आप एक getClass()समानता जांच का उपयोग कर सकते हैं , या instanceofयदि आप equalsऔर hashCodeविधियाँ बनाते हैं तो आप चेक का उपयोग कर सकते हैं final
छाया पुरुष

26

यह एक धार्मिक बहस का विषय है। दोनों दृष्टिकोणों से उनकी समस्याएं हैं।

  • का प्रयोग करें instanceof और आप उपवर्गों महत्वपूर्ण सदस्य कभी नहीं जोड़ सकते हैं।
  • GetClass का उपयोग करें और आप Liskov प्रतिस्थापन सिद्धांत का उल्लंघन करते हैं।

बलोच ने प्रभावी जावा द्वितीय संस्करण में सलाह का एक और प्रासंगिक टुकड़ा दिया है :

  • आइटम 17: वंशानुक्रम के लिए डिज़ाइन और दस्तावेज़ या इसे प्रतिबंधित करें

1
getClassएलएसपी का उपयोग करने के बारे में कुछ भी नहीं होगा, जब तक कि आधार वर्ग विशेष रूप से एक साधन का दस्तावेज नहीं बनाता है, जिसके द्वारा विभिन्न उपवर्गों के उदाहरणों को बनाना संभव हो सकता है जो समान तुलना करते हैं। एलएसपी उल्लंघन आप क्या देखते हैं?
सुपरकैट

शायद इसका उपयोग rephrased के रूप में किया जाना चाहिए getClass और आप एलएसपी उल्लंघन के खतरे में उपप्रकार छोड़ देते हैं। बलोच का प्रभावी जावा में एक उदाहरण है - यहां भी चर्चा की गई है । उनका तर्क काफी हद तक यह है कि यह उन उप-प्रक्रियाओं को लागू करने वाले डेवलपर्स के लिए आश्चर्यजनक व्यवहार का परिणाम हो सकता है जो राज्य को जोड़ते नहीं हैं। मैं आपकी बात लेता हूं - दस्तावेज़ीकरण प्रमुख है।
मैकडॉवेल

2
अलग-अलग वर्गों के केवल दो उदाहरणों को कभी भी खुद को रिपोर्ट करना चाहिए समान है यदि वे एक सामान्य आधार वर्ग या इंटरफ़ेस से विरासत में मिले हैं जो परिभाषित करता है कि समानता का क्या अर्थ है [एक दर्शन जो कि जावा ने लागू किया है, कुछ संग्रह इंटरफेस के लिए IMHO, संदिग्ध] जब तक आधार वर्ग अनुबंध नहीं कहता है कि getClass()इस तथ्य से परे सार्थक नहीं माना जाना चाहिए कि प्रश्न में वर्ग आधार वर्ग के लिए परिवर्तनीय है, से वापसी को getClass()किसी अन्य संपत्ति की तरह माना जाना चाहिए जो उदाहरणों के बराबर होने के लिए मेल खाना चाहिए।
सुपरकैट

1
@eyalzba जहाँ instof_ का उपयोग किया जाता है यदि कोई उपवर्ग सदस्यों को अनुबंध के बराबर करता है तो यह सममित समानता आवश्यकता का उल्लंघन करेगा । गेटक्लास उपवर्गों का उपयोग करना कभी भी मूल प्रकार के बराबर नहीं हो सकता है। ऐसा नहीं है कि आपको वैसे भी बराबरी पर रहना चाहिए, लेकिन अगर आप ऐसा करते हैं तो यह व्यापार बंद है।
मैकडॉवेल

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

23

यदि मैं गलत हूं तो मुझे सुधारें, लेकिन getClass () तब उपयोगी होगा जब आप यह सुनिश्चित करना चाहेंगे कि आपका उदाहरण उस वर्ग का उपवर्ग नहीं है, जिसकी आप तुलना कर रहे हैं। यदि आप उस स्थिति में Instof का उपयोग करते हैं तो आप यह नहीं जान सकते कि क्योंकि:

class A { }

class B extends A { }

Object oA = new A();
Object oB = new B();

oA instanceof A => true
oA instanceof B => false
oB instanceof A => true // <================ HERE
oB instanceof B => true

oA.getClass().equals(A.class) => true
oA.getClass().equals(B.class) => false
oB.getClass().equals(A.class) => false // <===============HERE
oB.getClass().equals(B.class) => true

मेरे लिए यही कारण है
करालिहोनोस

5

यदि आप केवल यह सुनिश्चित करना चाहते हैं कि वर्ग मेल खाएगा तो उपयोग करें getClass() ==। यदि आप उपवर्गों का मिलान करना चाहते हैंinstanceof जरूरत है।

इसके अलावा, Instof एक अशक्त के खिलाफ मेल नहीं खाएगा लेकिन एक अशक्त के खिलाफ तुलना करने के लिए सुरक्षित है। इसलिए आपको इसकी जांच करने की आवश्यकता नहीं है।

if ( ! (obj instanceof MyClass) ) { return false; }

अपने दूसरे बिंदु को फिर से लिखें: उन्होंने पहले ही उल्लेख किया है कि प्रश्न में। "मैं आमतौर पर इंस्टोफ़ विकल्प की जांच करता हूं, और फिर अंदर जाकर 'if (obj == null)' चेक हटाता हूं।"
माइकल मायर्स

5

यह निर्भर करता है कि क्या आप विचार करते हैं कि किसी दिए गए वर्ग का उपवर्ग इसके माता-पिता के बराबर है या नहीं।

class LastName
{
(...)
}


class FamilyName
extends LastName
{
(..)
}

यहाँ मैं 'Instof' का उपयोग करूँगा, क्योंकि मैं चाहता हूँ कि LastName की तुलना FamilyName से की जाए

class Organism
{
}

class Gorilla extends Organism
{
}

यहाँ मैं 'getClass' का उपयोग करूँगा, क्योंकि वर्ग पहले से ही कहता है कि दोनों उदाहरण समान नहीं हैं।


3

Instof एक ही वर्ग या उसके उपवर्गों के उदाहरणों के लिए काम करता है

आप इसका उपयोग यह परीक्षण करने के लिए कर सकते हैं कि कोई ऑब्जेक्ट किसी वर्ग का उदाहरण है, किसी उपवर्ग का उदाहरण है, या किसी वर्ग का एक उदाहरण जो किसी विशेष इंटरफ़ेस को लागू करता है।

ArryList और RoleList दोनों ही उदाहरण सूची हैं

जबकि

getClass () == o.getClass () केवल तभी सही होगा जब दोनों ऑब्जेक्ट्स (यह और o) बिल्कुल एक ही क्लास के हों।

तो आप एक या दूसरे का उपयोग कर सकते हैं तुलना करने के लिए क्या जरूरत पर निर्भर करता है।

यदि आपका तर्क है: "एक वस्तु केवल अन्य के बराबर है यदि वे दोनों एक ही वर्ग हैं" तो आपको "समान" के लिए जाना चाहिए, जो मुझे लगता है कि अधिकांश मामले हैं।


3

दोनों विधियों में उनकी समस्याएं हैं।

यदि उपवर्ग पहचान बदलता है, तो आपको उनकी वास्तविक कक्षाओं की तुलना करने की आवश्यकता है। अन्यथा, आप सममित संपत्ति का उल्लंघन करते हैं। उदाहरण के लिए, विभिन्न प्रकार केPerson समान नहीं माना जाना चाहिए, भले ही उनका नाम एक ही हो।

हालाँकि, कुछ उपवर्ग पहचान नहीं बदलते हैं और इनका उपयोग करने की आवश्यकता होती है instanceof। उदाहरण के लिए, यदि हमारे पास अपरिवर्तनीय Shapeवस्तुओं का एक गुच्छा है , तो Rectangle1 की लंबाई और चौड़ाई के साथ इकाई के बराबर होना चाहिए Square

व्यवहार में, मुझे लगता है कि पूर्व का मामला सच होने की अधिक संभावना है। आमतौर पर, उपवर्ग आपकी पहचान का एक बुनियादी हिस्सा है और आपके माता-पिता के समान होने के अलावा आप एक छोटी सी चीज कर सकते हैं जो आपको समान नहीं बनाता है।


-1

वास्तव में उदाहरण की जाँच करें कि कोई वस्तु किसी पदानुक्रम से संबंधित है या नहीं। पूर्व: कार वस्तु वाहन वर्ग से संबंधित है। तो "नई कार () वाहन का उदाहरण" सही है। और "नई कार ()। GetClass ()। बराबरी (Vehical.class)" झूठी है, हालांकि कार ऑब्जेक्ट व्हीकलिकल क्लास से संबंधित है लेकिन इसे एक अलग प्रकार के रूप में वर्गीकृत किया गया है।

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