본문 바로가기
프로그래밍 언어/Java

열거 타입(Enum)

by 진진리 2023. 10. 20.
728x90

그동안 Java로 문제 풀이를 할 때 enum을 몰라서 string 배열 등을 사용했었는데

enum을 여러 번 듣게 되어서 한 번 정리 및 공부해보려고 한다.

 

enum

이러한 상수를 단순히 정수로 치부하지 말고 객체 지향적으로 객체화해서 관리하자는 취지

Java에서는 enum을 인터페이스와 같이 독립된 특수한 클래스로 구분

reference 타입으로 분류되며, enum 상수값은 힙 영역에 저장됨

일종의 클래스이지만 인스턴스화는 불가능: 고정된 정수들의 집합으로써 컴파일 타임에 모든 값을 알고 있어야 하기 때

  • 장점
    • 코드가 단순해지며 가독성이 좋아짐
    • 허용 가능한 값들을 제한하여 유형 안전을 제공
    • 구현의 의도가 열거임을 분명하게 나타낼 수 있음
    • switch문에서도 사용할 수 있음
    • 단순 상수와 비교해 IDE의 적극적인 지원을 받을 수 있음

 

  • enum 선언
enum Week{
    MONDAY, TUESDAY, WEDNESDAY, TURSDAY, FRIDAY, SATURDAY, SUNDAY
}

enum명은 클래스와 같이 첫 문자를 대문자로 하고 나머지는 소문자로 구성

관례적으로 열거 상수는 모두 대문자로 작성

 

  • enum 참조 방식
// 열거타입 변수 = 열거타입.열거상수;
Week monday = Week.MONDAY;
Week sunday = Week.SUNDAY;

 

  • enum 메소드 종류
    • String name(): 열거 객체의 문자열을 리턴
    • int ordinal(): 열거 객체의 순번을 리턴
    • int compareTo(): 열거 객체를 비교해서 순번 차이를 리턴
    • enum valueOf( String name ): 문자열을 입력받아서 일치하는 열거 객체를 리턴
    • enum[] values(): 모든 열거 객체들을 배열로 리턴
Week w = Week.FRIDAY;

// 열거 객체의 문자열을 리턴
String weekName = w.name();
System.out.println(weekName); // Spring
Week w = Week.FRIDAY;

// 열거 객체의 순번(0부터 시작)을 리턴
// 전체 열거 객체 중 몇 번째 열거 객체인지 알려준다
int weekNum = w.ordinal();
System.out.println(weekNum); // 4
// 열거 객체를 비교해서 순번 차이를 리턴 (시작점을 어느 열거 객체의 기준으로 몇번째 위치하는지)
Week w1 = Week.TUESDAY; // 2
Week w2 = Week.SATURDAY; // 6

// 열거 객체가 매개값의 열거 객체보다 순번이 빠르다 → 음수를 리턴
int compare1 = w1.compareTo(w2); // SATURDAY 기준으로 TUESDAY 위치 (6에서 2가 되기 위한 값)
System.out.println(compare1); // -4

// 열거 객체가 매개값의 열거 객체보다 순번이 늦다 → 양수를 리턴
int compare2 = w2.compareTo(w1); // TUESDAY 기준으로 SATURDAY 위치 (2에서 6가 되기 위한 값)
System.out.println(compare2); // 4
// 문자열을 입력받아서 일치하는 열거 객체를 리턴
Week w3 = Week.valueOf("SUNDAY"); // w3 변수는 Week.SUNDAY 열거 객체를 참조하게 됨
System.out.println(w3); // SUNDAY
// 모든 열거 객체들을 배열로 리턴
Week[] w4 = Week.values();

System.out.println(Arrays.toString(w4)); // [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]

for (Week type : Week.values()) { // 열거 순회
    System.out.println(type);  // 순서대로 열거 객체 출력
}

 

  • java.lang.Enum 클래스

Enum 클래스는 java.lang.Enum이라는 클래스의 상속을 받음

java.lang.Enum 클래스도 Object 클래스를 자동 상속해서 enum에서듀 Object 클래스의 메소드를 그대로 사용 가능

하지만 다음 4개의 메소드를 오버라이딩하지 못함

  1. clone()
  2. finalize()
  3. hashCode()
  4. equals()

 

  • enum 매핑: 상수를 가져올 때 상수의 고유의 값(value)를 출력하게 만들고 싶을 때 사용
// enum 매핑 클래스
enum Season {
    SPRING("봄"),
    SUMMER("여름"),
    FALL("가을"),
    WINTER("겨울");
	
    // 문자열을 저장할 필드
    private String season;

	// 생성자 (싱글톤)
    private Season(String season) {
        this.season = season;
    }

	// Getter
    public String getSeason() {
        return season;
    }
}
public static void main(String[] args) throws Exception {
    Season s = Season.SUMMER;
    System.out.println(s.name()); // 열거 객체명 출력 : SUMMER
    System.out.println(s.getSeason()); // 매핑된 열거 데이터 출력 : 봄
}

 

  • enum 확장

단순히 상수 값을 넘어서 상수 메소드로서도 이용이 가능

추상 메소드를 정의해서 각 상수마다 익명 클래스처럼 메소드 재정의를 하게 해서 각 상수마다 다른 역할을 하는 메소드를 갖게 되는 원리

-> 상수 상태와 행위를 한 곳에서 관리 가능.

-> 상수마다 다르게 동작하는 로직이 필요할 때 객체 지향적인 코드로 유지 보수하기 용이함

enum Operation {
    PLUS("+") {
        public double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS("-") {
        public double apply(double x, double y) {
            return x - y;
        }
    },
    MULTI("*") {
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/") {
        public double apply(double x, double y) {
            return x / y;
        }
    };

    // 클래스 생성자와 멤버
    private final String symbol;
    Operation(String symbol) {
        this.symbol = symbol;
    }

    // toString을 재정의하여 열거 객체의 매핑된 문자열을 반환하도록
    @Override
    public String toString() {
        return symbol;
    }

    // 열거 객체의 메소드에 사용될 추상 메소드 정의
    public abstract double apply(double x, double y);
}

- 람다식으로 더 깔끔하게

// 함수형 인터페이스 임포트
import java.util.function.DoubleBinaryOperator;

enum Operation {
    PLUS("+", (x, y) -> x + y),
    MINUS("-", (x, y) -> x - y),
    TIMES("*", (x, y) -> x * y),
    DIVIDE("/", (x, y) -> x / y);

    private final DoubleBinaryOperator op; // 람다식을 저장할 필드

    private final String symbol;

    Operation(String symbol, DoubleBinaryOperator op) {
        this.symbol = symbol;
        this.op = op;
    }

    @Override
    public String toString() { return symbol; }

    public double apply(double x, double y) {
        return op.applyAsDouble(x, y);
    }
}
public static void main(String[] args) {
    double x = 2.5;
    double y = 5.0;

    // Operation 상수집합의 PLUS 상수를 정의
    Operation plus = Operation.PLUS;

    // enum 매핑값 출력
    String name = plus.toString();
    System.out.println(name); // +

    // enum 확장 메소드 실행
    double result = plus.apply(x, y); // 덧셈을 수행하는 메소드 (Operation.PLUS.apply(x, y) 로 해도됨)
    System.out.println(result); // 7.5

    // ------------------------------------------------------------------- //

    // Operation 상수집합의 PLUS 상수를 정의
    Operation multi = Operation.MULTI;

    String name = plus.toString();
    System.out.println(name); // *

    // enum 확장 메소드 실행
    double result2 = multi.apply(x, y); // 곱셈을 수행하는 메소드
    System.out.println(result2); // 12.5
}

 

+++ 익명 클래스: 재사용할 필요가 없는 일회성 클래스를 기존의 자식 클래스와 같이 상속시켜 사용하지 않고 익명으로 인라인으로 한방에 선언하여 사용

++++ 익명 클래스 예시

// 부모 클래스
class Animal {
    public String bark() {
        return "동물이 웁니다";
    }
}

public class Main {
    public static void main(String[] args) {
        // 익명 클래스 : 클래스 정의와 객체화를 동시에. 일회성으로 사용
        Animal dog = new Animal() {
        	@Override
            public String bark() {
                return "개가 짖습니다";
            }
        }; // 단 익명 클래스는 끝에 세미콜론을 반드시 붙여 주어야 한다.
        	
        // 익명 클래스 객체 사용
        dog.bark();
    }
}

'프로그래밍 언어 > Java' 카테고리의 다른 글

정규표현식  (0) 2023.10.17
포함관계와 추상화 구현 순서  (0) 2023.10.16
추상 클래스와 인터페이스 비교  (0) 2023.10.16
자주 쓰는 함수  (0) 2023.10.10
자료형 String  (0) 2023.09.21