java - 이란 - 자바 enum




자바 열거 형 멤버 비교:== 또는 equals()? (10)

Java enum은 개인 생성자와 정적 정적 멤버가있는 클래스로 컴파일된다는 것을 알고 있습니다. 주어진 enum의 두 멤버를 비교할 때, 나는 항상 .equals() 사용했다.

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

그러나, 그냥 equals () 대신 equals 연산자 == 를 사용하는 몇 가지 코드를 발견했습니다.

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

어떤 연산자를 사용해야합니까?


tl; dr

또 다른 옵션은 Objects.equals 유틸리티 메소드입니다.

Objects.equals( thisEnum , thatEnum )

Objects.equals

.equals () 대신 연산자 ==와 동일합니다.

어떤 연산자를 사용해야합니까?

세 번째 옵션은 Java 7 이상에 추가 된 Objects 유틸리티 클래스에있는 static Objects.equals 메소드입니다.

다음은 Month 열거 형을 사용하는 예제입니다.

boolean areEqual = Objects.equals( Month.FEBRUARY , Month.JUNE ) ;  // Returns `false`.

은혜

이 방법에 몇 가지 이점이 있습니다.

  • 무효 안전
    • 둘 다 null ➙ true
    • null 또는 끔 false 중 하나
    • NullPointerException 을 throw 할 위험이 없습니다.
  • 작고 읽기 쉬운

작동 원리

Objects.equals 사용하는 논리는 무엇입니까?

OpenJDKJava 10 소스 코드 에서 직접 확인하십시오.

return (a == b) || (a != null && a.equals(b));

enum 사용할 수 있습니까?

예 : enum에는 == 를 사용하여 인스턴스를 비교할 수있는 엄격한 인스턴스 컨트롤이 있습니다. 다음은 언어 사양에서 제공하는 보증입니다 (저의 강조).

JLS 8.9 열거 형

열거 형에는 열거 형 상수로 정의 된 인스턴스 이외의 인스턴스가 없습니다.

열거 형을 명시 적으로 인스턴스화하려고하면 컴파일 타임 오류가 발생합니다. enumfinal clone 메서드는 Enum enum 상수를 복제 할 수 없도록하고 직렬화 메커니즘을 사용하여 특수 처리를 수행하면 비 직렬화의 결과로 중복 인스턴스가 생성되지 않습니다. 열거 형의 반사적 인 인스턴스 생성은 금지됩니다. 함께,이 네 가지 것들 enum 형식의 인스턴스를 enum 상수에 의해 정의 된 것보다 존재하지 않도록합니다.

enum 상수의 인스턴스가 하나뿐이기 때문에 둘 중 하나가 enum 상수를 참조하는 경우 두 개의 객체 참조를 비교할 때 equals 메서드 대신 == 연산자를 사용할 수 있습니다. Enumequals 메소드는 인수에 super.equals 를 호출하고 결과를 반환하여 ID 비교를 수행하는 final 메소드입니다.

이 보장은 Josh Bloch가 강력하게 권장하는 바에 따르면, 싱글 톤 패턴 사용을 고집한다면 구현하는 가장 좋은 방법은 단일 요소 enum 을 사용하는 것입니다 ( Effective Java 2nd Edition, Item 3 : 전용 생성자 또는 열거 형 , 또한 Singleton의 스레드 안전성 )

==equals 의 차이점은 무엇입니까?

다시 말해, 일반적으로 ==equals 대한 실행 가능한 대안이 아니라고 말할 필요가 있습니다. 그러나 ( enum 과 같이) 고려해야 할 두 가지 중요한 차이점이 있습니다.

== 절대로 NullPointerException throw하지 않습니다.

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!

해당되는 경우 == 사용해야합니까?

Bloch는 인스턴스를 적절하게 제어 할 수있는 불변 클래스가 클라이언트에게 == 사용할 수 있음을 보장 할 수 있다고 언급했습니다. enum 은 구체적으로 예시됩니다.

항목 1 : 생성자 대신 정적 팩토리 메소드 고려

[...] 그것은 불변 클래스가 두 개의 동일한 인스턴스가 존재하지 않는다는 것을 보장합니다 : a==b 경우 a.equals(b) . 클래스가이 보증을하면 클라이언트는 equals(Object) 메서드 대신 == 연산자를 사용할 수 있으므로 성능이 향상 될 수 있습니다. Enum 형은이 보증을 제공합니다.

요약하면 enum== 를 사용하는 인수는 다음과 같습니다.

  • 그것은 작동합니다.
  • 더 빠릅니다.
  • 그것은 런타임에 더 안전합니다.
  • 컴파일시에 더 안전합니다.

나는 polygenelubricants 답변을 보완하고 싶습니다 :

나는 개인적으로 equals ()를 선호한다. 그러나 유형 호환성 검사를 호소합니다. 나는 이것이 중요한 한계라고 생각한다.

컴파일 할 때 유형 호환성 검사를하려면 열거 형에서 사용자 정의 함수를 선언하고 사용하십시오.

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

이를 통해 NPE 보호, 컴파일시 쉽게 읽을 수있는 코드 및 유형 호환성 검사를 모두 사용할 수 있습니다.

또한 열거 형에 대해 UNDEFINED 값을 추가하는 것이 좋습니다.


나는 명시 적으로 == 연산자와 equals() 메서드 사이의이 특정한 차이점을 강조하고 싶습니다.

equals() 메서드는 객체 의 내용 이 관련된 참조 변수가 참조되는지 여부를 확인하기 위한 것 입니다.

== 연산자는 관련된 참조 변수 가 동일한 객체를 참조하는지 여부를 확인합니다.

응용 프로그램에서 필요에 따라 차별화를 제공하는 것은 구현 클래스에 달려 있습니다.

그렇지 않은 경우 기본 동작은 Object 클래스에서 제공 한대로 (Java에서) http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals(java.lang.Object) :

Object 클래스의 equals 메서드는 Object 가능한 가장 동등한 동등성 관계를 구현합니다. 즉, null 이외의 참조 치 xy 에 대해서,이 메소드는 xy 가 같은 객체를 참조하고있는 경우에만 true 돌려줍니다 ( x == ytrue ).


다음 두 가지를 비교하기위한 원유 타이밍 테스트입니다.

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());
    }   

}

IF를 한 번에 하나씩 주석으로 처리하십시오. 다음은 디스 어셈블 된 바이트 코드에서 위에서 두 가지 비교입니다.

 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

첫 번째 (같음)는 가상 호출을 수행하고 스택에서 return boolean을 테스트합니다. 두 번째 (==)는 스택에서 객체 주소를 직접 비교합니다. 첫 번째 경우에는 더 많은 활동이 있습니다.

나는이 테스트를 한 번에 하나씩 IF를 여러 번 실행했습니다. "=="은 약간 더 빠릅니다.


두 개의 enum 값을 비교하기 위해 == 를 사용하면 각 enum 상수에 대해 하나의 객체 만 있기 때문에 작동합니다.

참고로 equals() 과 같이 작성하면 == 를 사용하여 null 안전 코드를 작성할 필요가 없습니다.

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

이것은 당신이 반드시 따라야 하는 왼쪽에서 상수 비교로 알려진 모범 사례입니다.


열거 형 ==로 열거 된 이유는 정의 된 각 인스턴스가 싱글 톤이기도하기 때문입니다. 따라서 ==를 사용하는 ID 비교는 항상 작동합니다.

그러나 열거 형과 작동하기 때문에 ==를 사용하면 모든 코드가 열거 형의 사용법과 밀접하게 결합됩니다.

예 : 열거 형은 인터페이스를 구현할 수 있습니다. 현재 Interface1을 구현하는 enum을 사용한다고 가정하십시오. 나중에, 누군가가 그것을 변경하거나 동일한 인터페이스의 구현으로서 새로운 클래스 Impl1을 도입합니다. Impl1의 인스턴스를 사용하기 시작하면 ==를 사용했기 때문에 변경하고 테스트 할 코드가 많이 생깁니다.

따라서 정당한 이득이 없으면 좋은 행동으로 간주되는 것을 따라하는 것이 가장 좋습니다.


열거 형은 public static final field (immutable)에 의해 선언 된 각 열거 형 상수에 대해 하나의 인스턴스 (예 : 싱글 톤)를 반환하는 클래스로 equals() 메서드를 사용하는 대신 동등성을 검사하는 데 사용할 수 있습니다.


중간에 열거 형은 정수의 집합입니다. "=="는 두 개의 정수를 비교하는 것처럼 유효하고 적절합니다.


즉, 장단점이 있습니다.

한편으로는 다른 답변에서 설명한 것처럼 == 를 사용하는 것이 좋습니다.

반면에 어떤 이유에서든 열거 형을 다른 접근법 (일반 클래스 인스턴스)으로 바꾸면 == 를) 사용합니다. (BTDT.)





enums