본문 바로가기
자바/스터디

[ 자바 스터디] 11주차 과제 - 열거형(Enum)

by jeonghaemin 2021. 1. 29.
728x90

본 게시글은 백기선 님의 live-study 과제를 수행하면서 작성한 글입니다.

목표

자바의 열거형에 대해 학습하세요.

학습할 것 (필수)

  • enum 정의하는 방법
  • enum이 제공하는 메서드 (values()와 valueOf())
  • java.lang.Enum
  • EnumSet

열거형(Enum)이란?

열거형은 서로 관련이 있는 여러 상수를 편리하게 선언하기 위한 것으로, C언어와 달리 자바에서는 원래 열거형이 존재하지 않았지만 JDK1.5부터 새로 추가되었다.

C언어의 열거형은 타입이 달라도 값이 같다면 == 비교에서 true를 리턴 하지만, 자바의 열거형은 '타입에 안전한 열거형'이라서 값이 같더라도 타입이 다르면 컴파일 에러가 발생한다.

enum 정의하는 방법

enum 열거형이름 {상수명1, 상수명2, ... }

예를 들어 학점을 나타내는 열거형을 정의하면 다음과 같다.

enum Grade { A, B, C, D, F }

열거형에 정의한 상수는 '열거형이름.상수명' 형태로 사용할 수 있다.

public class Main {
    public static void main(String[] args) {
        Student kim = new Student("kim", Grade.A);

        if(kim.getGrade() == Grade.A) {
            System.out.println("열거형은 == 비교 가능");
        }

        //<, >과 같은 비교연산자는 사용할 수 없고,
        //compareTo() 메서드로 비교한다.
        //같으면 0, 왼쪽이 크면 양수, 오른쪽이 크면 음수 반환
        System.out.println(Grade.A.compareTo(Grade.B));
    }

    static class Student {

        private String name;
        private Grade grade;

        public Student(String name, Grade grade) {
            this.name = name;
            this.grade = grade;
        }

        public String getName() {
            return name;
        }

        public Grade getGrade() {
            return grade;
        }
    }
}

열거형에 멤버 추가하기

Enum 클래스에 정의된 ordinal() 메서드가 열거형 상수가 정의된 순서를 반환해주긴 하지만, 상수 값이 불연속적이거나 필요에 따라 열거형에 멤버를 추가해 값을 따로 지정해 줄 수 있다.

public enum Grade {
    //()안에 상수 값 지정.
    A(100),B(80),C(60),D(50),F(30);

    //지정된 값을 저장할 수 있는 인스턴스 변수와 생성자를 추가해야한다.
    private final int minScore;

    //열거형 생성자의 접근 제어자는 묵시적으로 private이기 때문에 객체를 생성할 수 없다.
    Grade(int minScore) {
        this.minScore = minScore;
    }

    //외부에서 값을 불러오기위한 용도
    public int getMinScore() {
        return minScore;
    }
}

예제에는 인스턴스 변수를 minScore 1개 사용했지만, 클래스와 마찬가지로 여러 개를 사용할 수 있다.

열거형에 추상 메서드 추가하기

열거형에 추상 메서드를 선언하는 일은 거의 없으므로 가볍게 참고만 하자.

public enum Grade {
    A(100) {
        @Override
        void abstractMethod() { /*code*/ }

        }
    },
    B(80){
        @Override
        void abstractMethod() { /*code*/ }

        }
    },
    C(60){
        @Override
        void abstractMethod() { /*code*/ }

    },

        ...생략

    abstract void abstractMethod();

}

enum이 제공하는 메소드 (values()와 valueOf())

열거형에는 컴파일러가 자동으로 추가해주는 메서드가 있다.

  • values() : 열거형의 모든 상수를 배열에 담아 반환.
  • valueOf() : 열거형 상수의 이름으로 문자열 상수에 대한 참조를 얻을 수 있다.
Grade[] grades = Grade.values();

for (Grade grade : grades) {
	System.out.println("grade = " + grade);
}
        
/*
결과
grade = A
grade = B
grade = C
grade = D
grade = F
*/

System.out.println(Grade.valueOf("A") == Grade.A); //결과 : true

java.lang.Enum

java.lang.Enum 클래스는 모든 열거형의 조상 클래스로 다음과 같은 메서드들이 정의되어 있다.

  • Class getDeclaringCase() : 열거형의 class객체를 반환.
  • String name() : 열거형 상수의 이름을 반환.
  • int ordinal() : 열거형 상수가 저장된 순서를 반환.(0부터 시작)
  • static <T extends Enum <T>> T valueOf(Class enumType, String name) : 지정한 열거형에서 name과 일치하는 열거형 상수를 반환
Grade grade = Grade.A;

System.out.println(grade.getDeclaringClass()); //결과: 패키지명.Grade

System.out.println(grade.name()); //결과 : A

System.out.println(grade.ordinal());// 결과 : 0, 열거형을 선언할 떄 가장 먼저 선언한 상수이기 떄문에 0.

System.out.println(Enum.valueOf(Grade.class, "A")); //결과 : A

EnumSet

java.util 패키지에 있으며, Set인터페이스를 상속하고 있다.

//지정한 열거형의 모든 상수를 포함한 set 생성.
EnumSet<Grade> allOfSet = EnumSet.allOf(Grade.class);

//지정한 열거형 상수를 포함하는 set 생성.
EnumSet<Grade> partitionGrade = EnumSet.of(Grade.B, Grade.C);

//열거형의 모든 상수 중 지정한 열거형 set에 포함되지 않은 열거형 상수 set 생.
EnumSet<Grade> complementOfSet = EnumSet.complementOf(partitionGrade);

//지정 열성거형의 비어있는 set 생성.
EnumSet<Grade> noneOfSet = EnumSet.noneOf(Grade.class);

//지정한 범위의 열거형 상수 set 생성.
EnumSet<Grade> rangeSet = EnumSet.range(Grade.B, Grade.D);

System.out.println("allOfSet = " + allOfSet);
System.out.println("partitionGrade = " + partitionGrade);
System.out.println("complementOfSet = " + complementOfSet);
System.out.println("noneOfSet = " + noneOfSet);
System.out.println("rangeSet = " + rangeSet);

/*
결과
allOfSet = [A, B, C, D, F]
partitionGrade = [B, C]
complementOfSet = [A, D, F]
noneOfSet = []
rangeSet = [B, C, D]
*/

Enum의 내부 구현

열거형의 상수는 내부적으로 객체로 구현되어 있다. 즉 A, B, C, D, F 상수 하나하나가 모두 Grade의 객체라는 뜻이다.

enum Grade { A, B, C, D, F }

위의 enum을 클래스로 정의하면 다음과 같다.

public class Grade {

    static final Grade A = new Grade("A");
    static final Grade B = new Grade("B");
    static final Grade C = new Grade("C");
    static final Grade D = new Grade("D");
    static final Grade F = new Grade("F");

    private String name;

    public Grade(String name) {
        this.name = name;
    }
}

열거형 상수 하나 하나가 static 상수이고 객체이기 때문에 '==' 비교가 가능했던 것이다.

참고

  • 자바의 정석 3판(남궁성 저)

댓글