glenn-syj / more-effective-java

이펙티브 자바를 읽으며 자바를 더 효율적으로 공부합니다
4 stars 5 forks source link

[MEJ-008] enum class 내 ordinal() 메서드 보충 설명 #166

Closed glenn-syj closed 1 month ago

glenn-syj commented 2 months ago

based on: #160 by @FickleBoBo

들어가며

ordinal() 메서드에 대해서 글을 잘 작성해주셨는데요. (ordinal() 이라는 오타는 넘어갑시다!) 저는 보충적으로 그럼에도 왜 ordinal() 메서드가 있는지를 탐구해보았습니다.

ordinal()의 쓰임

Java 8 Oracle 공식 문서에서는 ordinal() 메서드를 아래와 같이 소개합니다.

Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.

요약하자면, ordinal() 메서드는 프로그래머의 편의보다도 EnumSet이나 EnumMap과 같이 enum에 기반한 데이터 타입을 위해 쓰이는 메서드라고 합니다. EnumMap은 @yngbao97 이 다루고 있으니, EnumSet을 잠깐 살펴보겠습니다.

void addRange(E from, E to) {
        elements = (-1L >>>  (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
}

위 코드는 EnumSet 내부의 addRange 메서드입니다. 이 함수에서 elements는 비트 벡터를 표현하는 64비트 크기의 long 타입 멤법 변수입니다. 여기에서 -1L은 모든 비트가 1인 경우를 의미합니다. 이는 -1L >>> (from.ordinal() - to.ordinal() - 1)에 대해서, from.ordinal() 만큼 비트를 왼쪽으로 이동시키는데요.

쉽게 말하자면, 이 코드는 from에 해당하는 enum value의 위치부터, to에 해당하는 enum value의 위치까지 모든 상수를 포함하도록 만드는 코드입니다. ordinal()은 외부에서 특정한 값 참조를 위해 이용하기보다는, 내부 메서드를 효율적으로 구현하기 위해 사용된다는 점을 다시 볼 수 있습니다.

결국 ordinal()은 특정 위치나 논리적으로 구분되는 위치보다는, 의미적으로 구분되는 범위를 위해서는 이용해봐도 괜찮지 않을까하는 생각도 드네요.

References

https://docs.oracle.com/javase%2F8%2Fdocs%2Fapi%2F%2F/java/lang/Enum.html

FickleBoBo commented 2 months ago

메서드 내부에서 oridinal을 사용하는 예시를 보니 좀 더 이해가 되는 것 같습니다.

addRange 코드에 대해서는 완벽히 이해하기 약간 어렵지만 from과 to의 oridinal 범위에 대해 비트 연산을 한다고 봤을 때, 배열의 인덱스처럼 원소에 종속되지 않는 고유한 순서값으로만 사용하는 것에 의미가 있는 것 같습니다.

좋은 탐구 감사합니다!