본문 바로가기
Java/Java Basic

[Java Basic] 40 - 열거형(enum) 개요와 사용법

by Rosmary 2022. 9. 13.
728x90
반응형

 

 

 

Java에서 날짜와 시간을 다루는 클래스 중 Calendar라는 클래스가 java.util 패키지 내에 존재한다. Calendar 클래스는 특정 날짜의 연도, 월, 일, 시, 분, 초 등을 필드값으로 지정하고 있다. Calendar는 get이라는 매서드의 매개변수로 날짜 필드값을 입력받는데, 필드값에 의해 날짜의 특정 지정값을 화면에 출력하는 것이 가능하다.

 

 

 

위의 내용을 클래스로 작성할 수 있을까? Calendar 객체를 매개변수로 받아 인스턴스를 생성하고, myGet()이라는 매서드로 날짜 데이터를 추출하는 클래스를 만들어보려한다.

 

 

 

클래스가 정상 동작하는지 확인해보자.

 

 

 

지금이야 필자가 Calendar의 필드값을 단 6개만 표시했기 때문에 코드가 그나마 덜 복잡해보이지만, 실제 Calendar의 필드값을 전부 클래스 내에 작성한다면 가독성이 떨어질 수 밖에 없는 것은 너무나도 당연해진다.

 

 

 

이렇게 연관된 데이터를 보기 좋게 묶기 위해 Java에서 제공하는 것이 하나 있는데 바로 enum, 열거형이라고 불리는 것이다. 원래 C에 존재하던 개념인데 Java에서는 jdk 1.5 부터 적용이 되었다고 한다. C를 다루어보셨던 분들이라면 열거형의 개념에 대해 이해하는데 큰 어려움은 없을 것이다. 

 

 

 

1. 열거형 타입의 정의와 사용

 

열거형 타입의 선언은 매우 쉽다. enum이라는 키워드 뒤에 변수명을 입력하고 배열 형식으로 필드값 이름을 작성하면 된다. 간단하게 카드 놀이에 사용되는 Spade, Clover, Heart, Diamond를 열거형으로 표시해보자.

 

 

 

 

enum은 java의 기본 타입과 달리, 반드시 클래스 내부에 작성하지 않아도 된다. 사실 enum을 잘 보면 모양 자체가 클래스와 매우 유사하다는 것을 알 수 있다.

 

 

 

따라서 서두에 보았던 Calendar의 필드값 역시 열거형으로 표시하는 것이 가능하다. 열거형을 별도로 분리하고 기존의 DateExtracter 클래스를 변경하면 아래와 같은 모양이 된다.

 

 

 

위의 예시를 보면 알 수 있듯이 사용 방법 역시 매우 단순하다. 마치 클래스 내의 상수를 호출하듯이 사용하면 된다. 특이한 것은 enum 내부에 들어가 있는 상수 변수들은 String이나 int와 같은 Java의 기본형으로 분류되지 않고, enum 변수명으로 타입이 분류된다는 것이다. 즉, 일종의 객체 변수로 판단된다. 이러한 이유로 필자가 별도 생성한 myGet() 매서드 역시 매개인자로 받는 데이터의 타입이 Field로 지정된 것이다.

 

 

 

열거형 이전에 클래스로 정수형 상수로 표시한 코드를 보면 각각의 상수들이 필드값을 가지고 있는 것을 확인했었다.그럼 열거형 내부의 각 상수들은 어떠한 값을 가지고 있는 것일까? 

 

 

 

2. Enum 클래스와 매서드로 불연속 상수값 지정하기

 

열거형 역시 열거형을 조금 더 효율적으로 다루기 위한 매서드만 정의한 Enum이라는 클래스가 java.lang 패키지에 정의되어 있다. Java의 모든 객체가 Object를 공통 부모 객체로 인식하듯이, 열거형 자료는 Enum 클래스를 공통 부모 객체로 인식한다. Enum을 상속한다는 말이다.

 

 

 

따라서 Enum에 정의되어 있는 매서드는 열거형의 개별 상수에서 호출하여 사용하는 것이 가능하다.

 

열거형 상수가 정의된 순서 및 이름을 반환하는 매서드는 ordinal()과 name()이라는 매서드다. 

 

 

또한 하나의 열거형 묶음에 정의된 모든 상수 요소를 배열 형태로 반환하는 매서드인 values()와, 열거형 상수 요소의 이름으로 상수에 대한 참조를 가능하도록 하는 valueOf()라는 매서드가 존재한다.

 

 

 

만약 열거형이 둘 이상 정의되어 있는 경우라면, 각 요소들이 가지는 정수값은 동일할 것이다. 따라서 다음과 같이 ordinal() 매서드와 비교 연산자를 사용하여 서로 다른 두 열거형의 상수 요소 값을 비교하는 것도 가능하다.

 

 

 

 

현재 필자가 만든 열거형 자료들은 요소들이 정수를 0부터 순차적으로 보유하게 된다. 예를 들면 YEAR는 첫 요소이므로 0을, MONTH는 1, DATE 2... 로 말이다. 그럼, 이 값들을 불연속적으로 저장할 수 있는 방법은 없을까? Calendar의 예시에서도 보았듯이 YEAR, MONTH, DATE가 연속적인 값이 아닌 1, 2, 5로 불연속적인 값을 가지고 있기 때문에 일반적인 열거형의 선언으로는 유지보수가 복잡한 코드를 사용할 수 밖에 없다는 문제가 있다.

 

case 문 내에 지정된 index 값은 수동으로 넣은 값이라 추후 코드 수정 시에도 비효율적이다.

 

 

앞서 언급한데로, 열거형은 클래스와 매우 유사한 형태를 띄고 있다. 이 말은, 열거형 역시 생성자와 매서드 생성이 가능하다는 의미다. 만약 상수 값을 불연속적으로 지정하고 싶다면 아래와 같이 진행하면 된다.

 

 

 

저장된 값은 ordinal() 매서드가 아닌 새로 작성한 getValue()로 반환받는데, ordinal() 매서드는 열거형 묶음 내에 위치한 요소들의 순번(Order)만을 나타내는 값이기 때문에 생성자로 정수 값을 지정한다고 해도 변화가 없기 때문이다.

 

참고로 enum은 클래스와 동일하게 생성자 생성은 가능하나 제어자가 private으로 기본 적용되어있기 때문에 enum 코드 외부에서는 인스턴스 생성이 불가능하다.

 

위에서 새로 정의한 열거형을 DateExtractor에 적용하면 아래와 같이 동일한 결과가 나타남을 알 수 있다. 하지만 훨씬 더 깔끔하고 가독성 높은 코드다.

 

 

 

 

3.열거형 내부 추상 매서드 정의

 

누차 언급했던대로 열거형은 클래스와 유사하다. 따라서 일반 매서드 뿐만 아니라 추상 매서드(Abstract Method) 작성도 가능하다. 하지만 열거형 내부에 정의된 추상 매서드는 상속을 통해 구현되는 것이 아니라, 열거형 요소에 구현한다는 차이점이 있다. 

 

 

 

필자가 printValue()라는 추상 매서드를 enum Field 내부에 정의하자마자, 바로 각 요소들이 에러를 보여준다. 에러의 내용은 매우 단순한데, printValue()가 추상매서드로 선언되었음에도 각 요소들이 이를 구현하지 않았다는 것이다. 

 

 

 

열거형 요소는 단순하게보면 상수같은 느낌인데 어떻게 코드를 구현하라는 것인지 감이 잘 오지 않는다. 열거형 상수에 매서드를 구현하는 방법은 아주 단순한데, 열거형 상수 옆에 중괄호{}를 추가하고 괄호 사이에 추상 매서드를 정의하면 된다.

 

 

 

위의 코드는 Main에서 아무리 열심히 돌려봐야 "Abstract Method"라는 문구가 단 한 줄도 출력되지 않는다. 사실 열거형의  Abstract는 개별 상수 요소들이 가지고 있는 값을 수정해야하는 경우, 그러나 모든 요소가 동일한 작업을 거치지 않아야 하는 상황에서 사용하기 때문이다. 

 

조금 다른 예시로, 지하철과 버스의 운임 비용을 열거형으로 나타내보자. 지하철과 버스비 모두 가본 요금은 각각 1450, 1250원이고, 버스는 10km까지만 기본 요금을 적용하고 다음 1km 마다 50원씩 추가가 된다고 하자. 지하철은 반면에 20km 까지 기본 요금을 적용하나 1km 초과 시 100원씩 운임이 추가된다고 해보자. 그럼 열거형 코드는 아래와 같이 작성할 수 있게 된다.

 

 

 

만약 열거형 내 추상 매서드가 없다면 각기 다른 상황에 대한 운임요금 계산 코드를 작성하기가 매우 까다로웠을 것이다. 두 운송수단의 기본 거리, 추가 요금에 대해 변수를 생성해야하는 것은 물론이고 if-else if 문이 떡칠되어 필자가 자주 언급하는 유지보수와 수정도 용이치 않을 정도로 가독성이 낮아지는 코드가 완성되었을 것이다. 하지만 추상 매서드를 적용하면, 선언하는 변수의 수를 최소한도로 줄임과 동시에 각기 다른 운송수단에 대한 운임 요금 계산 코드를 각각의 상수 바로 근처에서 관리할 수 있게 된다.

 

결과는 아래와 같이 나타난다.

 

 

 

추상 매서드를 열거형 내부에 정의하는 경우, 추상 매서드의 호출은 열거형 상수 요소를 통해 호출하게 된다. 

 

 

 

 


 

 

다음 포스팅에서는 Annotation(애너테이션)에 대해 알아보려한다.

 

 

Fin.

반응형

댓글