[F-lab 모각코 챌린지 18일차] TIL

JeongheeKim·2023년 6월 18일

TIL

목록 보기
18/66

학습계획


  • Enum 정리

Today I Learned


1. Enum 출연 이전

과일 명에 숫자를 매칭하여 과일에 해당하는 코드처럼 사용하였다.

주석이 있어서 1번이 사과인건 알았지만 만약 주석이 지워지거나, 누군가 모르고 수정했다거나, 주석과 과일의 해당 코드를 사용하는 코드가 멀리 떨어져 있어서 1이 사과인 것을 알기 힘들다면?

package enumTest;

public class ConstantDemo {
    public static void main(String[] args) {
/**
         * 1. 사과
         * 2. 복숭아
         * 3. 바나나
         */int type = 1;

        switch (type){
            case 1:
                System.out.println(57);
                break;
            case 2:
                System.out.println(34);
                break;
            case 3:
                System.out.println(93);
                break;
        }

    }
}

소실의 위험이 있는 주석에서 한번 선언하면 더 이상 바뀌지 않은 final 키워드와 static 변수(=클래스 변수 : 메모리에 한번 할당되어 프로그램이 종료될 때 해제됨)로 선언하여 사용하기 편해졌다.

package enumTest;

public class ConstantDemo {

	private final static int APPLE = 1;
	private final static int PEACH = 2;
	private final static int BANANA = 3;

    public static void main(String[] args) {

        int type = 1;

        switch (type){
            case 1:
                System.out.println(57);
                break;
            case 2:
                System.out.println(34);
                break;
            case 3:
                System.out.println(93);
                break;
        }

    }
}

과일뿐만 아니라 다른 코드들이 추가된다면 코드는 상수 선언으로만 가득 찰 것이다. Constant Interface를 활용하여 리팩토링보자.

Constant Interface

상수만 정의한 인터페이스. 인터페이스의 경우 변수 등록 시 자동으로 public static final이 붙는다.
그러므로 어디서나 접근이 가능하다. Constant Interface를 Implemnet할 경우 상속 받은 클래스에서 상수 변수명을 사용할 수 있다.

또한 인터페이스로 선언하면서 APPLE이라는 동일한 상수명 컴파일러 에러를 피할 수 있었다.

package enumTest;

interface FRUIT{
    int APPLE = 1,PEACH = 2,  BANANA =3;
}

interface COMPANY{
    int APPLE = 1, GOOGLE = 2, ORACLE =3;
}

public class ConstantDemo {
        public static void main(String[] args) {

            if(FRUIT.APPLE == COMPANY.APPLE){
                System.out.println("과일애플과 기업애플이 같다고??");
            }

            int type = 1;

            switch (type){
                case 1:
                    System.out.println(57);
                    break;
                case 2:
                    System.out.println(34);
                    break;
                case 3:
                    System.out.println(93);
                    break;
            }

        }
    }

하지만 FRUIT.APPLE과 COMPANY.APPLE는 다른 개념의 코드로 작성하였지만 같은 것으로 인식( 동일한 int 데이터 타입으로 선언되어)되는 현상이 발생했다.

Fruit, Company 클래스 데이터 타입을 다르게 변경하여 비교가 되지 않는다.

각각의 변수는 final이라 불변이고, static이므로 인스턴스 생성하지 않아도 된다. 하지만 아래의 코드는 길이도 길고 복잡하고 또한 switch문에서 사용이 불가하다.

그리하여 Enum이라는 등장하였다..

package enumTest;

class Fruit{
     public static final Fruit APPLE = new Fruit();//자기 자신의 인스턴스를 상수 APPLE의 값으로 지정public static final Fruit PEACH = new Fruit();
     public static final Fruit BANANA = new Fruit();
}

class Company{
    public static final Fruit GOOGLE = new Fruit();
    public static final Fruit APPLE = new Fruit();
    public static final Fruit ORACLE = new Fruit();
}

public class ConstantDemo {
        public static void main(String[] args) {

            if(Fruit.APPLE == Company.APPLE){
                System.out.println("과일애플과 기업애플이 같아요");
            }else{
                System.out.println("과일애플과 기업애플이 같지않아요!!");
            }

            Fruit type = Fruit.APPLE;

            switch (type){
                case 1:
                    System.out.println(57);
                    break;
                case 2:
                    System.out.println(34);
                    break;
                case 3:
                    System.out.println(93);
                    break;
            }

        }
    }

2. Enum 정의하는 방법

Enum 이란?

  • 열거형 (enumerated type) - 서로 연관된 상수들의 집합 = 상수로만 구성된 클래스

위의 코드에서 Fruit, Company가 이에 해당한다.

Enum을 사용하는 이유

  • 코드가 단순해진다.
  • 인스턴스 생성과 상속을 방지한다.
  • 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 나타 낼 수 있다.
  • 상수이므로 값에 대한 동적 할당이 안된다.
accessModifier enum enumName{
//상수//메서드 정의
}
package enumTest;
/*
* class Week{
*   public static final Week SUNDAY = new Week();
*   public static final Week MONDAY = new Week();
*   public static final Week TUESDAY = new Week();
*   public static final Week WEDNESDAY = new Week();
*   public static final Week THURSDAY = new Week();
*   public static final Week FRIDAY = new Week();
*   public static final Week SATURDAY = new Week();
*
*/enum Week{
    SUNDAY(1,"First day"),//상수 선언 마다 위으 코드처럼 인스턴스화(생성자 호출)
    MONDAY(2,"Second day"),
    TUESDAY(3,"Third day"),
    WEDNESDAY(4,"Fourth day"),
    THURSDAY(5,"FIfth day"),
    FRIDAY(6,"Sixth day"),
    SATURDAY(7,"Seventh day");

    private final int code;
    private final String stringCode;

    Week(int code, String stringCode){
        System.out.println("Call Constructor "+this);
        this.code = code;
        this.stringCode = stringCode;
//전역변수 stringCode = 매개변수 (=지역변수)stringCode를 대입
    }//인스턴스 화 되면서 인스턴스를 만들기 위한 생성자 호출//지역변수가 전역변수보다 우선순위가 높으므로 this를 사용하지않으면 지역변수를 대입한다.public int getCode(){
        return code;
    }

    public String getStringCode(){
        return stringCode;
    }
}

public class ConstantDemo {
        public static void main(String[] args) {

            Week constantFromEnum = Week.MONDAY;
            System.out.println(constantFromEnum);
            System.out.println(constantFromEnum.getCode());
            System.out.println(constantFromEnum.getStringCode());
        }
    }

enum 자체가 클래스 이므로 생성자를 가질 수 있다.

Call Constructor가 7번이 출력된 것은 enum Week 클래스의 필드 수만큼 호출되었음을 확인할 수 있다. 각 각의 필드가 인스턴스 생성하면서 생성자를 호출했다는 이야기
하지만 enum 생성자의 접근제한자를 public으로 변경하면 에러가 발생한다. 이는 enum 클래스의 생성자의 접근 제한자는 private만 허용하고 있기 때문이다.

외부에서는 enum클래스를 인스턴스화할 수 없도록 막았다. enum클래스는 제한된 상수값을 가지는 클래스인데 public 제한자로 범위를 넓혔다면 다른 생성자가 다른 상수값을 추가할 수 있다.
또한, enum 생성자에 private 제한자를 붙이면 Modifier 'private' is redundant for enum constructors라는 메시지를 만날 수 있다. enum 클래스 생성자가 암시적으로 private여서 private 접근 제한자가 불필요하다고 메시지가 뜬것이다.

0개의 댓글