[JAVA] enum(열거형)이란

ILLION·2023년 3월 2일
0

JAVA

목록 보기
1/2

1. enum(열거형)이란

  • '열거형'은 JDK1.5에 추가된 자료형
  • 열거형도 Object 클래스를 상속하는 일종의 클래스. 그래서 생성자 뿐 아니라 인스턴스 변수와
    메소드 둘 다 가질 수 있다.
  • enum타입의 상수들마다 각각의 인스턴스가 생성된다.
  • 값을 비교할 때 값으로 비교할 뿐 아니라 타입까지 비교한다.

2. 열거형의 기본 사용법

enum 이름 {
	상수1, 상수2, .....
}

3. enum(열거형)이 있기 전과 후

enum타입이 생기기 전의 상수들을 표현하는 방법을 보자!

interface Const {
    int a = 0; //인터페이스 내에 변수를 선언할 경우 컴파일 시 public static final이 자동적으로 선언된다.
    public static final int b = 1; //직업 넣어도 무관하다.

}
public class InterfaceConst {
    public static void main(String[] args) {
        int i = Const.b;

        switch (i) {
            case Const.a:
                System.out.println("0 입니다.");
                break;
            case Const.b:
                System.out.println("1 입니다.");
                break;
            default:
                System.out.println("nothing");
        }
    }
}


이렇게 상수들을 하나의 인터페이스로 묶어서 선언한 것이 열거형이 나오기 이전의 방법이다.
하지만 인터페이스로 활용해서 상수들을 만들 때 발생하는 문제점이 있다. 이것도 예제로!!

interface PersonConst {
    int MAN = 1;
    int WOMAN = 2;

}
interface AnimalConst {
    int DOG = 1;
    int CAT = 2;
}
public class InterfaceConst {
    public static void main(String[] args) {
        // switch문을 통해서 특정 인물의 성별을 알고싶은 로직
        who(PersonConst.MAN);
        who(AnimalConst.DOG);
    }

    public static void who(int person) {
        switch (person) {
            case PersonConst.MAN:
                System.out.println("남성 입니다.");
                break;
            case PersonConst.WOMAN:
                System.out.println("여성 입니다.");
                break;
        }
    }
}


who메소드를 통해서 특정 인물의 성별을 나타내고 싶었지만
PersonConst.MAN의 값도 1, AnimalConst.DOG의 값도 1이기 때문에 컴파일링 상에선 맞는 문법이기 때문에 오류가 발생하지 않습니다.
이런 문제를 보완하기 위해 나온 게 열거형입니다.

열거형은 클래스와 성격이 매우 비슷하기 때문에 참조변수의 선언도 가능합니다. 단 참조변수로 선언하려면 열거형 내에 선언되어 있는 '상수값'만 대입이 가능합니다.

ex) EnumConst ec = EnumConst.열거형 값

enum EnumConst { // enum타입 생성하는 구문
    APPLE, BANANA, MELON
}
public class EnumClass {
    public static void main(String[] args) {
        EnumConst ec = EnumConst.APPLE;
        System.out.println(ec);

        switch (ec) {
            case APPLE:
                System.out.println("사과 입니다.");
                break;
            case BANANA:
                System.out.println("바나나 입니다.");
                break;
            case MELON:
                System.out.println("멜론 입니다.");
                break;
            default:
                System.out.println("nothing");
        }
    }
}

그럼 이번에는 앞에서 인터페이스로 활용해서 생긴 문제점을 열거형으로 해결하는 예시코드를 보여드리겠습니다.

enum PersonConst {
    MAN,
    WOMAN

}
enum AnimalConst {
    DOG,
    CAT
}
public class EnumConstClass {
    public static void main(String[] args) {
        who(PersonConst.MAN); // 정상작동
        //who(AnimalConst.DOG); // 컴파일 에러
    }

    public static void who(PersonConst person) { //파라미터가 PersonConst라는 데이터타입으로 지정
        switch (person) {
            case MAN:
                System.out.println("남성 입니다.");
                break;
            case WOMAN:
                System.out.println("여성 입니다.");
                break;
        }
    }
}


위 예제를 컴파일 하면 who(AnimalConst.DOG)의 호출문에 컴파일 에러가 발생합니다.
PersonConst타입의 값을 파라미터로 지정했기 때문에 AnimalConst타입의 값은 전달되지 않습니다.
인터페이스의 상수를 활용해서 나타났던 문제점이 enum(열거형)을 통해 해결되었습니다.

4. 열겨형 상수값간의 비교

Java의 enum 타입은 하나의 인스턴스로 제한되어 있기 때문에, == 연산자를 사용하여 두 enum 상수가 동일한 객체인지를 비교할 수 있습니다.
== 연산자는 두 객체의 메모리 주소가 같은지를 비교합니다. 따라서 enum 상수는 같은 인스턴스이기 때문에, == 연산자를 사용하여 비교할 수 있습니다.

enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

Day day1 = Day.MONDAY;
Day day2 = Day.MONDAY;

if (day1 == day2) {
    System.out.println("day1과 day2는 같은 객체입니다.");
}

주의할 점은 일반적인 객체 타입일 경우, == 연산자는 두 객체의 값이 아닌 메모리 주소를 비교하므로 객체의 값이 같아도 false를 반환할 수 있습니다. 이 경우 equals() 메소드를 사용해서 객체의 값을 비교할 수 있습니다.
즉, enum 상수는 하나의 인스턴스이므로 비교할 땐 == 연산자를 사용해 동일한 객체인지를 비교하는 것이 바람직합니다.

5. 클래스 내에 enum(열거형) 정의

열거형은 특정 클래스 내에 정의할 수 있다. 만약 특정 클래스에만 열거형 값을 사용하게 된다면 해당 클래스 내에 열거형을 정의하면 된다.

class SomethingClass { // SomethingClass 시작 지점
    enum PersonConst {
        MAN, WOMAN
    }

    private String name;
    private PersonConst sex;

    public SomethingClass(String name, String sex) {
        this.name = name;

        if (sex.equals("man")) {
            this.sex = PersonConst.MAN;
        } else {
            this.sex = PersonConst.WOMAN;
        }
    }

    @Override
    public String toString() {
        if (sex == PersonConst.MAN) {
            return name + "님은 " + sex + "입니다.";
        } else {
            return name + "님은 " + sex + "입니다.";
        }
    }
} // // SomethingClass 끝 지점
public class Test {
    public static void main(String[] args) {
        SomethingClass sc1 = new SomethingClass("길동", "man");
        SomethingClass sc2 = new SomethingClass("길순", "woman");

        System.out.println(sc1);
        System.out.println(sc2);
    }
}

열거형이 특정 클래스 내에 있기 때문에 열거형을 활용하기 위해서 클래스 내에서 구현하면 된다.
마찬가지로 열거형은 특정 클래스 내에 있기에 클래스를 인스턴스화 해서 활용해야 합니다.
만약 직접 열거형을 선언하게 될 경우 오류가 발생하게 됩니다.

6. 열거형의 값 정체(?)실체

잘 사용되진 않지만 특정 클래스 안에서 그 클래스타입으로 참조변수를 선언하고 또한 인스턴스를 생성할 수 있다.

class Person {
    public static final Person MAN = new Person();
    public static final Person WOMAN = new Person();

    @Override
    public String toString() {
        return "사람입니다.";
    }
}
public class InsideClassTest {
    public static void main(String[] args) {
        System.out.println(Person.MAN);
        System.out.println(Person.WOMAN);
    }
}

위 코드를 보고 다음 나올 코드를 보게 되면 열거형의 값들이 해당 자료형의 인스턴스라는 것을 알려주게 된다.

enum Person {
    MAN, // == public static final Person MAN = new Person();
    WOMAN; // == public static final Person WOMAN = new Person();

    @Override
    public String toString() {
        return "사람입니다.";
    }
}
public class InsideEnumTest {
    public static void main(String[] args) {
        System.out.println(Person.MAN);
        System.out.println(Person.WOMAN);
    }
}

Person클래스 내에 인스턴스를 생성하고 main메소드에서 해당 객체를 호출했을 때와 Person 열거형에 해당하는 상수를 호출 했을 때가 같다. 즉 열거형 값은 Person 열거형의 인스턴스를 참조하는 참조변수라는 것이다.

7. 열거형의 생성자

열거형은 클래스와 마찬가지로 생성자를 정의할 수 있다. 클래스처럼 생성자가 없으면 default 생성자가 넣어진다. 열거형의 생성자를 만들 때 접근 제어자는 무조건 private으로 선언되어야 한다. 그렇게 되면 직접 인스턴스를 생성하는 것은 불가능하다. 무조건 private접근제어자로 정의해야 하는 이유는 enum(열거형)의 인스턴스가 프로그램 실행 중에 변경될 수 없도록 보장하기 위해서입니다. 열거형은 기본적으로 고정된 상수값을 나타내는데 인스턴스를 직접 생성했을 때 값이 변경되는 예기치 않은 문제가 발생할 수도 있기에 private제어자로 정의해야 합니다.

enum Person {
    MAN, WOMAN;

    private Person() { //생략가능
        System.out.println("열거형 값을 호출 했을 때 생성자 호출");
    }

    @Override
    public String toString() {
        return "사람입니다.";
    }
}
public class InsideEnumTest {
    public static void main(String[] args) {
        System.out.println(Person.MAN);
    }
}

위 예제의 결과를 보고 헷갈릴 수도 있습니다. 결론적으로 쉽게 얘기하자면
1. main메소드에서 Person.MAN을 호출
2. Person열거형의 값들은 Person 인스턴스를 참조하는 참조변수이다
MAN == public static final Person MAN = new Person();
WOMAN == public static final Person WOMAN = new Person();
그렇기 때문에 Person.MAN <- 한번 호출 했어도 2개의 참조변수가 있기에 생성자가 2번 호출됩니다.
3. toString메소드 호출
4. return된 값을 println메소드와 함께 출력

7-1 열거형의 필드를 통해 생성자 정의 방법

enum Person {
    MAN(30), WOMAN(25);

    int age;
    private Person(int age) {
        this.age = age;
        System.out.println("열거형 값을 호출 했을 때 생성자 호출");
    }

    @Override
    public String toString() {
        return age +"세 사람입니다.";
    }
}
public class InsideEnumTest {
    public static void main(String[] args) {
        System.out.println(Person.MAN);
    }
}

profile
결과를 중요시하기보단 과정을 중요하게 생각하는 마음가짐

0개의 댓글