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 할 위험이 없습니다.
- 둘 다 null ➙
- 작고 읽기 쉬운
작동 원리
Objects.equals
사용하는 논리는 무엇입니까?
OpenJDK 의 Java 10 소스 코드 에서 직접 확인하십시오.
return (a == b) || (a != null && a.equals(b));
enum
사용할 수 있습니까?
예 : enum에는 ==
를 사용하여 인스턴스를 비교할 수있는 엄격한 인스턴스 컨트롤이 있습니다. 다음은 언어 사양에서 제공하는 보증입니다 (저의 강조).
JLS 8.9 열거 형
열거 형에는 열거 형 상수로 정의 된 인스턴스 이외의 인스턴스가 없습니다.
열거 형을 명시 적으로 인스턴스화하려고하면 컴파일 타임 오류가 발생합니다.
enum
의final clone
메서드는Enum
enum
상수를 복제 할 수 없도록하고 직렬화 메커니즘을 사용하여 특수 처리를 수행하면 비 직렬화의 결과로 중복 인스턴스가 생성되지 않습니다. 열거 형의 반사적 인 인스턴스 생성은 금지됩니다. 함께,이 네 가지 것들enum
형식의 인스턴스를enum
상수에 의해 정의 된 것보다 존재하지 않도록합니다.각
enum
상수의 인스턴스가 하나뿐이기 때문에 둘 중 하나가enum
상수를 참조하는 경우 두 개의 객체 참조를 비교할 때equals
메서드 대신==
연산자를 사용할 수 있습니다.Enum
의equals
메소드는 인수에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 이외의 참조 치x
및y
에 대해서,이 메소드는x
및y
가 같은 객체를 참조하고있는 경우에만true
돌려줍니다 (x == y
는true
).
다음 두 가지를 비교하기위한 원유 타이밍 테스트입니다.
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.)