java जावा एनम सदस्यों की तुलना करना:== या बराबर()?




enums (12)

मुझे पता है कि जावा एनम्स निजी रचनाकारों और सार्वजनिक स्थैतिक सदस्यों के समूह के साथ कक्षाओं में संकलित किए जाते हैं। किसी दिए गए enum के दो सदस्यों की तुलना करते समय, मैंने हमेशा उपयोग किया है .equals() , उदाहरण के लिए

public useEnums(SomeEnum a)
{
    if(a.equals(SomeEnum.SOME_ENUM_VALUE))
    {
        ...
    }
    ...
}

हालांकि, मैं बस कुछ कोड में आया जो .equals () के बजाय बराबर ऑपरेटर == का उपयोग करता है:

public useEnums2(SomeEnum a)
{
    if(a == SomeEnum.SOME_ENUM_VALUE)
    {
        ...
    }
    ...
}

मैं किस ऑपरेटर का उपयोग कर रहा हूं?


एनम्स कक्षाएं हैं जो public static final field (अपरिवर्तनीय) द्वारा घोषित प्रत्येक गणना के लिए एक उदाहरण (सिंगलेट्स की तरह) लौटाती हैं ताकि == ऑपरेटर का उपयोग equals() विधि के बजाय उनकी समानता की जांच के लिए किया जा सके


दोनों तकनीकी रूप से सही हैं। यदि आप .equals() के लिए स्रोत कोड .equals() , तो यह बस == .equals() हो जाता है।

मैं == उपयोग करता हूं, हालांकि, यह शून्य सुरक्षित होगा।


संक्षेप में, दोनों पेशेवर और विपक्ष है।

एक ओर, इसका जवाब == का उपयोग करने के फायदे हैं, जैसा कि अन्य उत्तरों में वर्णित है।

दूसरी तरफ, यदि आप किसी भी कारण से एक अलग दृष्टिकोण (सामान्य श्रेणी के उदाहरण) के साथ enums को प्रतिस्थापित करते हैं, तो इस्तेमाल किया == आपको काटता है। (BTDT।)


दोनों की तुलना करने के लिए यहां एक क्रूड टाइमिंग टेस्ट है:

import java.util.Date;

public class EnumCompareSpeedTest {

    static enum TestEnum {ONE, TWO, THREE }

    public static void main(String [] args) {

        Date before = new Date();
        int c = 0;

        for(int y=0;y<5;++y) {
            for(int x=0;x<Integer.MAX_VALUE;++x) {
                if(TestEnum.ONE.equals(TestEnum.TWO)) {++c;}
                if(TestEnum.ONE == TestEnum.TWO){++c;}              
            }
        }

        System.out.println(new Date().getTime() - before.getTime());
    }   

}

एक समय में आईएफएस को टिप्पणी करें। उपरोक्त दो तुलनाओं को अलग-अलग बाइट-कोड में यहां दिया गया है:

 21  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 24  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 27  invokevirtual EnumCompareSpeedTest$TestEnum.equals(java.lang.Object) : boolean [28]
 30  ifeq 36

 36  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 39  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 42  if_acmpne 48

पहला (बराबर) वर्चुअल कॉल करता है और स्टैक से रिटर्न बूलियन का परीक्षण करता है। दूसरा (==) सीधे ऑब्जेक्ट पते को स्टैक से तुलना करता है। पहले मामले में और गतिविधि है।

मैंने कई बार आईएफएस के साथ इस परीक्षण को कई बार चलाया। "==" कभी इतना तेज़ है।


Enum स्थिरांक की तुलना करने के लिए == अलावा किसी अन्य चीज़ का उपयोग बकवास है। यह class वस्तुओं की तुलना equals साथ करना equals - ऐसा मत करो!

हालांकि, सूर्य जेडीके 6277781 में एक बुरा बग (बगआईड 6277781 ) था और इससे पहले ऐतिहासिक कारणों से दिलचस्प हो सकता है। इस बग ने deserialized enums पर == उचित उपयोग को रोका, हालांकि यह तर्कसंगत रूप से कोने के मामले में कुछ हद तक है।


बीच में Enum निरंतर पूर्णांक का एक सेट है। "==" उतना मान्य और उचित है जितना कि आपने दो पूर्णांक की तुलना की है।


क्या == enum पर इस्तेमाल किया जा सकता है?

हां: enums में कड़े उदाहरण नियंत्रण हैं जो आपको उदाहरणों की तुलना करने के लिए == का उपयोग करने की अनुमति देता है। भाषा विनिर्देश (मेरे द्वारा जोर) द्वारा प्रदान की गई गारंटी यहां दी गई है:

जेएलएस 8.9 एनम्स

एक enum प्रकार के enum स्थिरांक द्वारा परिभाषित उन लोगों के अलावा कोई उदाहरण नहीं है।

यह एक enum प्रकार को स्पष्ट रूप से तत्काल करने का प्रयास करने के लिए एक संकलन-समय त्रुटि है। Enum में final clone विधि यह सुनिश्चित करती है कि enum स्थिरांक को कभी भी क्लोन नहीं किया जा सकता है, और धारावाहिक तंत्र द्वारा विशेष उपचार सुनिश्चित करता है कि deserialization के परिणामस्वरूप डुप्लिकेट उदाहरण कभी नहीं बनाए जाते हैं। Enum प्रकार के प्रतिबिंबित तत्काल निषिद्ध है। साथ में, ये चार चीजें सुनिश्चित करती हैं कि enum स्थिरांक द्वारा परिभाषित लोगों के अलावा एक enum प्रकार का कोई उदाहरण मौजूद नहीं है।

चूंकि प्रत्येक enum स्थिरता का केवल एक उदाहरण है, दो ऑब्जेक्ट संदर्भों की तुलना करते समय == ऑपरेटर को equals विधि के स्थान पर उपयोग करने की अनुमति है यदि यह ज्ञात है कि उनमें से कम से कम एक enum स्थिरांक को संदर्भित करता है । ( super.equals में equals विधि एक final विधि है जो केवल अपने तर्क पर super.equals को आमंत्रित करती है और परिणाम देता है, इस प्रकार पहचान तुलना कर रही है।)

यह गारंटी पर्याप्त मजबूत है कि जोश ब्लोच ने सिफारिश की है कि यदि आप सिंगलटन पैटर्न का उपयोग करने का आग्रह करते हैं, तो इसे लागू करने का सबसे अच्छा तरीका एकल तत्व तत्व का उपयोग करना है (देखें: प्रभावी जावा द्वितीय संस्करण, आइटम 3: सिंगलटन संपत्ति को लागू करें एक निजी कन्स्ट्रक्टर या एनम प्रकार ; सिंगलटन में थ्रेड सुरक्षा भी)

== और equals बीच अंतर क्या हैं?

एक अनुस्मारक के रूप में, यह कहा जाना चाहिए कि आम तौर पर, == equals लिए व्यवहार्य विकल्प नहीं equals । जब यह होता है, हालांकि (जैसे enum साथ), विचार करने के लिए दो महत्वपूर्ण अंतर हैं:

== कभी भी NullPointerException फेंकता नहीं है

enum Color { BLACK, WHITE };

Color nothing = null;
if (nothing == Color.BLACK);      // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException

== संकलन समय पर संगतता जांच प्रकार के अधीन है

enum Color { BLACK, WHITE };
enum Chiral { LEFT, RIGHT };

if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine
if (Color.BLACK == Chiral.LEFT);      // DOESN'T COMPILE!!! Incompatible types!

लागू होने पर == का उपयोग किया जाना चाहिए?

ब्लोच विशेष रूप से उल्लेख करता है कि अपरिवर्तनीय वर्ग जिनके पास उनके उदाहरणों पर उचित नियंत्रण है, वे अपने ग्राहकों को गारंटी दे सकते हैं कि == उपयोग योग्य है। enum विशेष रूप से उदाहरण के लिए उल्लेख किया गया है।

आइटम 1: रचनाकारों के बजाय स्थैतिक फैक्ट्री विधियों पर विचार करें

[...] यह एक अपरिवर्तनीय वर्ग को गारंटी देने की अनुमति देता है कि कोई भी दो बराबर उदाहरण मौजूद नहीं हैं: a.equals(b) यदि और केवल अगर a==b । यदि कोई वर्ग इस गारंटी को बनाता है, तो उसके ग्राहक equals(Object) विधि के बजाय == ऑपरेटर का उपयोग कर सकते हैं, जिसके परिणामस्वरूप बेहतर प्रदर्शन हो सकता है। एनम प्रकार इस गारंटी प्रदान करते हैं।

संक्षेप में, enum पर == का उपयोग करने के लिए तर्क हैं:

  • यह काम करता हैं।
  • यह तेज है।
  • रन-टाइम पर यह सुरक्षित है।
  • यह संकलन समय पर सुरक्षित है।

Enum के मामले में दोनों सही और सही हैं !!


मैं polygenelubricants उत्तर पूरक करना चाहता हूँ:

मैं व्यक्तिगत रूप से बराबर पसंद करता हूं ()। लेकिन यह प्रकार संगतता जांच झील। जो मुझे लगता है वह एक महत्वपूर्ण सीमा है।

संकलन समय पर टाइप संगतता जांच करने के लिए, अपने enum में एक कस्टम फ़ंक्शन घोषित करें और उपयोग करें।

public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable

इसके साथ, आपको दोनों समाधानों का पूरा लाभ मिला: एनपीई संरक्षण, कोड पढ़ने में आसान और संकलन समय पर संगतता जांच टाइप करें।

मैं enum के लिए एक निश्चित मूल्य जोड़ने की भी सिफारिश करता हूं।


आप Enums की तुलना करने के लिए: ==, बराबर () या स्विच () ब्लॉक का उपयोग कर सकते हैं, सभी तकनीकी रूप से सत्य हैं और आपकी आवश्यकता को पूरा करेंगे।

Enum के सामान्य संचालन के बारे में और जानने के लिए इस ट्यूटोरियल की जांच करें: जावा में Enums का उपयोग कैसे करें


जैसा कि अन्य ने कहा है, ज्यादातर मामलों में == और .equals() दोनों काम करते हैं। संकलन समय निश्चितता है कि आप ऑब्जेक्ट्स के पूरी तरह से अलग-अलग प्रकार की तुलना नहीं कर रहे हैं, जिन्हें दूसरों ने इंगित किया है वह वैध और फायदेमंद है, हालांकि दो अलग-अलग संकलन समय प्रकारों की वस्तुओं की तुलना करने की विशेष प्रकार की बग भी FindBugs (और शायद द्वारा ग्रहण / IntelliJ संकलन समय निरीक्षण), तो जावा संकलक इसे खोजने में इतना अतिरिक्त सुरक्षा नहीं जोड़ता है।

तथापि:

  1. तथ्य यह है कि == कभी भी मेरे दिमाग में एनपीई फेंकता नहीं है == का नुकसान है। वहां कभी भी enum प्रकारों को null होने की आवश्यकता नहीं होनी चाहिए, क्योंकि कोई भी अतिरिक्त स्थिति जिसे आप null माध्यम से व्यक्त करना चाहते हैं, उसे अतिरिक्त उदाहरण के रूप में enum में जोड़ा जा सकता है। यदि यह अप्रत्याशित रूप से null , तो मैं बदले में == चुपचाप मूल्यांकन करने की तुलना में एनपीई चाहता हूं। इसलिए मैं रन-टाइम राय पर सुरक्षित से असहमत हूं; आदत में शामिल होना बेहतर है कि कभी भी enum मानों को @Nullable होने @Nullable
  2. तर्क है कि == तेज है भी फर्जी है। ज्यादातर मामलों में आप एक चर पर .equals() को कॉल करेंगे जिसका संकलन समय प्रकार enum वर्ग है, और उन मामलों में संकलक यह जान सकता है कि यह == जैसा है (क्योंकि एक enum की equals() विधि कर सकते हैं ओवरराइड नहीं किया जाएगा) और फ़ंक्शन कॉल को ऑप्टिमाइज़ कर सकते हैं। मुझे यकीन नहीं है कि संकलक वर्तमान में ऐसा करता है, लेकिन यदि यह नहीं करता है, और जावा में समग्र रूप से प्रदर्शन समस्या साबित होता है, तो मैं 100,000 जावा प्रोग्रामर सूट के लिए अपनी प्रोग्रामिंग शैली को बदलने के बजाय संकलक को ठीक करना चाहता हूं एक विशेष संकलक संस्करण की प्रदर्शन विशेषताओं।
  3. enums वस्तुएं हैं। अन्य सभी ऑब्जेक्ट प्रकारों के लिए मानक तुलना है .equals() , नहीं == । मुझे लगता है कि enums लिए अपवाद बनाना खतरनाक है क्योंकि आप गलती से ऑब्जेक्ट्स की तुलना में equals() बजाय == साथ तुलना कर सकते हैं, विशेष रूप से यदि आप एक गैर-एनम कक्षा में एक enum refactor। इस तरह के एक रिफैक्टरिंग के मामले में, उपरोक्त से यह कार्य बिंदु गलत है। अपने आप को यह समझाने के लिए कि == का उपयोग सही है, आपको यह जांचने की आवश्यकता है कि प्रश्न में मूल्य या तो एक enum या primitive है; यदि यह एक गैर-वर्ग वर्ग था, तो यह गलत होगा लेकिन याद करना आसान होगा क्योंकि कोड अभी भी संकलित होगा। एकमात्र मामला जब .equals() का उपयोग गलत होगा यदि प्रश्न में मूल्य प्राइमेटिव थे; उस स्थिति में, कोड संकलित नहीं होगा, इसलिए इसे याद करना बहुत मुश्किल है। इसलिए, .equals() को सही के रूप में पहचानना बहुत आसान है, और भविष्य के रिफैक्टरिंग के खिलाफ सुरक्षित है।

मुझे वास्तव में लगता है कि जावा भाषा को बाएं हाथ के मूल्य पर .equals () को कॉल करने के लिए ऑब्जेक्ट्स पर == परिभाषित किया जाना चाहिए था, और ऑब्जेक्ट पहचान के लिए एक अलग ऑपरेटर पेश करना चाहिए था, लेकिन ऐसा नहीं है कि जावा को कैसे परिभाषित किया गया था।

संक्षेप में, मुझे अभी भी लगता है कि तर्क enum प्रकारों के लिए .equals() का उपयोग करने के पक्ष में हैं।


मैं equals बजाय == का उपयोग करना पसंद करता हूं:

अन्य कारण, यहां पहले से चर्चा की गई अन्य लोगों के अलावा, क्या आप इसे समझने के बिना एक बग पेश कर सकते हैं। मान लें कि आपके पास यह enums है जो बिल्कुल वही है लेकिन अलग pacakges में (यह आम नहीं है, लेकिन यह हो सकता है):

पहला enum :

package first.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

दूसरा enum:

package second.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

तो मान लीजिए कि आप item.category में अगली item.category उपयोग करते हैं जो पहले. first.pckg.Category लेकिन आप इसे बिना किसी एहसास के पहले दूसरे enum ( second.pckg.Category ) आयात करते हैं:

import second.pckg.Category;
...

Category.JAZZ.equals(item.getCategory())

तो आप हमेशा के लिए false item.getCategory() क्योंकि एक अलग enum है हालांकि आप सच उम्मीद करते हैं क्योंकि item.getCategory() है। और यह देखना मुश्किल हो सकता है।

इसलिए, यदि आप इसके बजाय ऑपरेटर == उपयोग करते हैं तो आपके पास संकलन त्रुटि होगी:

ऑपरेटर == "second.pckg.Category", "first.pckg.Category" पर लागू नहीं किया जा सकता

import second.pckg.Category; 
...

Category.JAZZ == item.getCategory() 




enums