본문 바로가기
BackEnd/Java

자바 Enum 타입 속 모든 비밀: 정의, 컴파일러, 싱글톤

by 규난 2023. 10. 25.
728x90

목차

  1. 정의
  2. 사용법
  3. java.lang.Enum과 컴파일러
  4. enum tpye은 singleton?
  5. 사용 시 주의 사항
  6. 결론
  7. reference

 

1.  정의

오라클 자바 튜토리얼 공식 홈페이지에서는 Enum을 주로 연관된 상수들의 집합을 정의하는 데 사용하는 데이터 유형이라고 소개하고 있습니다.

오라클 자바 튜토리얼에서 소개하는 Enum Types

 

2.  사용법

자바에서는 enum keyword를 사용하여 enum type을 정의하며, 필드는 상수이기 때문에 대문자로 표시해야 합니다.

간단한 코드 예시를 통해 enum type의 정의와 사용법에 대해서 알아보도록 하겠습니다.

enum type 코드 예시

왼쪽 사진처럼 enum type을 정의 후 테스트 코드를 통해 바로 출력하게 되면 어떤 결과가 나오게 될까요?

enum type Day의 실행 결과

테스트 코드 실행 결과를 보시면 위에서 정의한 필드명이 출력되는 것을 볼 수 있습니다. 

저는 필드 값이 초기화도 안 되어 있고 인스턴스 생성도 하지 않았으며 그리고 static keyword가 붙어 있지 않음에도 불구하고 코드 예시처럼 enum type을 바로 사용할 수 있는 이유와 왜 저런 출력값이 나왔을까?에 대한 궁금증이 생겼습니다.

 

3.  java.lang.Enum과 컴파일러

위에서 제가 언급했던 모든 부분들이 왜 가능했는지 결론부터 말씀드리면 바로 컴파일러 덕분입니다.

오라클 자바 튜토리얼 공식 홈페이지에서는 enum type은 암시적으로 java.lang.Enum 클래스(앞으로 Enum 클래스라고 줄여서 언급하겠습니다.)를 확장한다고 설명하고 있습니다.

enum type과 Enum의 관계

 

정말 enum type은 Enum 클래스를 확장하고 있을까요??

javac 명령어를 통해 컴파일 후 얻은 바이트 코드를 읽기 좋게 javap 명령어로 디어셈블한 결과를 보도록 하겠습니다.

enum type Day의 컴파일된 코드

 

컴파일된 코드를 보면서 어느 부분이 바뀌었는지 살펴보도록 하겠습니다.

enum keyword가 final class로 바뀌었고 Enum 클래스를 확장하는 코드가 추가가 됐습니다.

그리고 enum type에 선언한 필드가 Day type으로 결정되고 public static final keyword가 추가된 것을 볼 수 있습니다.

이로써 제가 가졌던 static keyword에 대한 궁금증은 풀렸지만 아직 인스턴스의 생성과 필드 초기화에 대해서는 궁금증이 풀리지 않았습니다.

 

javap 명령어에 v 옵션을 사용해서 바이트 코드를 더 자세히 살펴보도록 하겠습니다.

(-v 옵션을 사용하면 runtime constant pool과 더불어서 여러 정보들을 출력하기 때문에 코드가 너무 길어져서 일부분만 캡쳐했습니다.)

-v 옵션을 추가한 컴파일된 코드

빨간색으로 밑줄이 그어진 static {}; 코드를 살펴보겠습니다.

이 코드는 static initializer block입니다. 이 block은 객체의 참조가 일어나거나 클래스 로딩 순간 딱 한 번만 실행되는 block입니다.

enum type을 컴파일하게 되면 컴파일러가 static initializer block을 추가하여 Day 클래스 내부에 선언된 정적 상수 필드에 대해서 초기화해주는 코드를 추가해 주게 됩니다. 드디어 제가 가졌던 궁금증이 다 풀렸습니다!

 

4.  enum type은 singleton?

enum type을 사용해보신 개발자분들은 enum type은 singleton이다 라는 말을 한 번 쯤은 들어보셨을 거 같은데요 singleton이라면 밑의 테스트 코드가 통과를 해야할텐데 한 번 실행해 보도록 하겠습니다.

enum type의 singleton 검증

테스트 결과는 통과입니다. enum type은 어떻게 singleton 객체가 될 수 있는 걸까요?

이유를 말씀드리면 enum type 생성자의 접근 제어자는 private 또는 package-private만 사용할 수 있습니다. 또한 static initializer block을 통해 딱 한 번만 인스턴스와 필드의 초기화가 이루어지기 때문입니다.

 

5.  사용 시 주의 사항

enum type은 일반 클래스와 마찬가지로 상태와 행위를 가질 수 있습니다.

enum type의 상태와 행위

 

코드를 보시면 description이라는 상태와 getDescription, setDescription이라는 행위(메서드)를 가지는 것을 보실 수 있습니다.

위에서 말씀드린 것처럼 enum type은 singleton 객체입니다. 즉, 멀티 스레드 환경에서는 상태를 바꿀 수 있는 행위인 setDescription 같은 메서드는 원하지 않은 결과가 나올 수 있기 때문에 상태도 꼭 final 키워드를 사용해 상수로 사용하는 것이 좋습니다.

상태를 바꾸는 안좋은 코드 예시

 

6.  결론

정리해서 말씀드리면 컴파일 시 컴파일러를 통해 enum type은 java.lang.Enum을 확장합니다. 그리고 컴파일러를 통해 확장뿐만 아니라 추가적으로 많은 코드와 키워드들이 부가적으로 붙게 되며 이로 인해 개발자는 편하게 enum type을 정의하고 사용할 수 있게 됩니다. 마지막으로 enum type은 상태와 행위를 가질 수 있고 singleton 객체이기 때문에 멀티 스레드 환경에서는 상태가 바뀌지 않게 주의해서 사용해야 됩니다.

 

7.  reference

https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

728x90

'BackEnd > Java' 카테고리의 다른 글

java에서 사용하는 Hash Collision 해결 방법  (1) 2023.11.06
BigDecimal 사용 이유  (0) 2023.10.19
Java Virtual Machine  (2) 2023.10.14
equals() 메서드와 hashCode() 메서드  (0) 2023.09.16
Stream  (0) 2023.08.20