Java 열거 형은 개인 생성자와 많은 공개 정적 멤버가있는 클래스로 컴파일된다는 것을 알고 있습니다. 주어진 열거 형의 두 멤버를 비교할 때 항상 사용했습니다 .equals()
.
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
그러나 방금 ==
.equals () 대신 equals 연산자를 사용하는 코드를 발견했습니다 .
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
어떤 연산자를 사용해야합니까?
답변
둘 다 기술적으로 정확합니다. 에 대한 소스 코드를 살펴보면 .equals()
간단히 연기됩니다 ==
.
내가 사용 ==
하는이 null 안전 할 것 같은, 그러나.
답변
수 ==
에 사용 enum
?
예 : 열거 형에는 인스턴스 ==
를 비교하는 데 사용할 수있는 엄격한 인스턴스 컨트롤이 있습니다 . 언어 사양에서 제공하는 보증은 다음과 같습니다 (강조 표시).
JLS 8.9 열거 형
열거 형에는 열거 형 상수로 정의 된 인스턴스 이외의 인스턴스가 없습니다.
열거 형 유형을 명시 적으로 인스턴스화하려고 시도하면 컴파일 타임 오류입니다. 이
final clone
방법을 사용Enum
하면enum
상수를 복제 할 수 없으며 직렬화 메커니즘에 의한 특수 처리를 통해 역 직렬화의 결과로 중복 인스턴스가 작성되지 않습니다. 열거 형 유형의 반사 인스턴스화는 금지됩니다. 이 네 가지를 함께 사용enum
하면enum
상수에 의해 정의 된 것 이상의 유형 인스턴스가 존재하지 않습니다 .각
enum
상수에는 하나의 인스턴스 만 있기 때문에 두 개 객체 참조 중 하나 이상이 상수 를 나타내는 것으로 알려진 경우 두 객체 참조를 비교할 때 메소드 대신 연산자 를 사용할 수==
equals
enum
있습니다. (의equals
방법Enum
A는final
그것이 단지 호출 방법에super.equals
따라서 식별 비교를 수행하는 인수 및 리턴 결과에).
이 보장은 Josh Bloch가 권장하는 것보다 강력합니다. 싱글 톤 패턴 사용을 고집하는 경우이를 구현하는 가장 좋은 방법은 단일 요소를 사용하는 것입니다 enum
( 유효한 Java 2 판, 항목 3 : 개인 생성자 또는 열거 형 ; Singleton의 스레드 안전성 )
의 차이점은 무엇입니까 ==
와는 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!
==
해당되는 경우 사용해야합니까 ?
Bloch는 인스턴스를 적절히 제어 할 수있는 불변 클래스 ==
가 사용 가능한 클라이언트를 보장 할 수 있다고 구체적으로 언급합니다 . enum
구체적으로 예시 적으로 언급된다.
항목 1 : 생성자 대신 정적 팩토리 메소드 고려
[…] 그것은 불변 클래스가 두 개의 동일한 인스턴스가 존재하지 않도록 보장합니다 :
a.equals(b)
if and only ifa==b
. 클래스가이 보증을하면 클라이언트는==
대신에 연산자를 사용할 수 있습니다 .equals(Object)
메소드 성능을 향상시킬 수 있습니다. 열거 형은이 보증을 제공합니다.
==
on 을 사용하기위한 인수 enum
는 다음과 같습니다.
- 효과가있다.
- 더 빠릅니다.
- 런타임에 더 안전합니다.
- 컴파일 타임에 더 안전합니다.
답변
사용 ==
각 열거 형 정수에 대해 하나의 객체가 있기 때문에,이 개 열거 값 작품을 비교.
참고로, ==
다음 equals()
과 같이 작성하면 실제로 널 안전 코드를 작성하는 데 사용할 필요가 없습니다 .
public useEnums(final SomeEnum a) {
if (SomeEnum.SOME_ENUM_VALUE.equals(a)) {
…
}
…
}
이것은 반드시 왼쪽에서 상수 비교로 알려진 모범 사례 입니다.
답변
다른 사람이 말했듯이, 모두 ==
와.equals()
대부분의 경우에 작동합니다. 다른 사람들이 지적한 완전히 다른 유형의 객체를 비교하지 않는 컴파일 시간 확실성은 유효하고 유익하지만 FindBugs는 두 가지 다른 컴파일 시간 유형의 객체를 비교하는 특정 버그도 발견 할 수 있습니다 Eclipse / IntelliJ 컴파일 시간 검사)) Java 컴파일러는 안전성을 크게 추가하지 않습니다.
하나:
==
내 마음 속에 NPE 를 절대 던지지 않는다는 사실 은 단점 이다==
. 를 통해 표현하려는 추가 상태를 추가 인스턴스로 추가 할 수 있기 때문에enum
유형이 될 필요는 거의 없습니다 . 예상치 못한 경우 조용히 거짓으로 평가하는 것보다 NPE가 필요합니다 . 따라서 나는 그것이 런타임 의견에 더 안전하다는 것에 동의하지 않는다 . 값을 절대로 두지 않는 습관을들이는 것이 좋습니다.null
null
enum
null
==
enum
@Nullable
- 인수
==
입니다 빨리는 또한 가짜입니다. 대부분의 경우.equals()
컴파일 시간 유형이 enum 클래스 인 변수를 호출 하며,이 경우 컴파일러는==
(enum
‘equals()
메소드를 재정의 할 수 없기 때문에) 와 동일하다는 것을 알고 함수 호출을 최적화 할 수 있습니다 떨어져. 컴파일러가 현재이 작업을 수행하고 있는지 확실하지 않지만 그렇지 않은 경우 Java의 전반적인 성능 문제로 판명되면 10 만 명의 Java 프로그래머가 프로그래밍 스타일을 변경하도록 프로그래밍하는 것보다 컴파일러를 수정하는 것이 좋습니다 특정 컴파일러 버전의 성능 특성 enums
객체입니다. 다른 모든 객체 유형의 경우 표준 비교는.equals()
아닙니다==
. 예외enums
가==
아닌 객체를 비 대신 클래스로equals()
리팩토링하는 경우 실수 대신 객체를 대신 비교할 수 있기 때문에 예외를 만드는 것이 위험하다고 생각합니다enum
. 이러한 리팩토링의 경우, 위의 작동 지점이 잘못되었습니다.==
올바른 사용법을 확신하려면 문제의 가치enum
가 기본인지 또는 기본 인지 확인해야합니다 .enum
클래스 가 아닌 경우 코드가 여전히 컴파일되기 때문에 잘못되었지만 쉽게 놓칠 수 있습니다. 사용하는 유일한 경우.equals()
문제의 가치가 원시적이라면 틀릴 것이다. 이 경우 코드가 컴파일되지 않으므로 놓치기가 훨씬 어렵습니다. 따라서.equals()
올바른 것으로 식별하기가 훨씬 쉽고 향후 리팩토링에 대해 더 안전합니다.
실제로 Java 언어는 왼쪽 값에서 .equals ()를 호출하기 위해 Objects에 ==을 정의하고 객체 ID에 대해 별도의 연산자를 도입해야한다고 생각하지만 Java가 정의 된 방식은 아닙니다.
요약하자면, 나는 여전히 논쟁이 유형 에 사용 .equals()
하는 것을 선호한다고 생각합니다 enum
.
답변
나는 ==
대신에 사용하는 것을 선호합니다 equals
:
다른 이유는 여기에서 이미 논의한 다른 것들 외에도 버그를 깨닫지 않고 버그를 도입 할 수 있기 때문입니다. 정확히 같지만 분리 된 pacakges에있는이 열거 형이 있다고 가정합니다 (일반적이지는 않지만 발생할 수 있음).
첫 번째 열거 형 :
package first.pckg
public enum Category {
JAZZ,
ROCK,
POP,
POP_ROCK
}
두 번째 열거 형 :
package second.pckg
public enum Category {
JAZZ,
ROCK,
POP,
POP_ROCK
}
그런 다음에 다음과 같이 등호를 사용하는 가정 item.category
이다 first.pckg.Category
그러나 당신은 두 번째 열거 (수입 second.pckg.Category
그것을 실현하지 않고 첫 번째 대신) :
import second.pckg.Category;
...
Category.JAZZ.equals(item.getCategory())
당신은에 allways를 얻을 것이다 그래서 false
당신은 진정한 때문에 예상하지만 다른 열거입니다 때문 item.getCategory()
입니다 JAZZ
. 그리고보기 어려울 수 있습니다.
따라서 대신 연산자 ==
를 사용하면 컴파일 오류가 발생합니다.
operator ==는 “second.pckg.Category”, “first.pckg.Category”에 적용 할 수 없습니다
import second.pckg.Category;
...
Category.JAZZ == item.getCategory()
답변
다음은 두 가지를 비교하기위한 조잡한 타이밍 테스트입니다.
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
첫 번째 (동일)는 가상 호출을 수행하고 스택에서 리턴 부울을 테스트합니다. 두 번째 (==)는 스택에서 직접 객체 주소를 비교합니다. 첫 번째 경우에는 더 많은 활동이 있습니다.
한 번에 하나씩 두 IF로이 테스트를 여러 번 실행했습니다. “==”이 너무 빠릅니다.
답변
열거 형의 경우 모두 정확하고 옳습니다!