-
- enum(열거형) : enumerated type
서로 연관된 상수들의 집합(class, interface와 동급의 형식을 가지는 단위, 사실상 class)
클래스와 그 객체들(상수 하나당 자신의 인스턴스를 하나씩 만든다)
다음 둘은 같다. 전자를 많이 사용하기 때문에 이를 지원하기 위해 자바 enum이 생겨났다.
class Fruit{ public static final Fruit APPLE = new Fruit(); public static final Fruit PEACH = new Fruit(); public static final Fruit BANANA = new Fruit(); }
enum Fruit { APPLE, PEACH, BANANA }
- enum 효과
1) 상수가 필요할 때 상수 그룹 생성(상수 저장)
2) 서로 다른 상수 그룹에 대한 비교를 컴파일 시점에서 차단할 수 있다.
3) 상수 그룹 별로 클래스를 만든 것의 효과를 enum도 갖는다. (생성자, 필드, 메서드를 가질 수 있다)
4) 열거형이 가지고 있는 상수들을 .values()로 배열에 담아 하나하나 꺼낼 수 있다.
- enum 사용 이유
1) 코드가 단순해진다
2) 인스턴스 생성과 상속을 방지한다
3) 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 나타낼 수 있다.
- enum이 없다면?
변수를 지정하고 변수를 final로 처리하면 상수화된다.
또한 바뀌지 않을 값이므로 인스턴스 변수가 아니라 클래스 변수(static)로 지정한다.
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 = APPLE; switch(type) { case APPLE: System.out.println(57+" kcal"); break; case PEACH: System.out.println(34+" kcal"); break; case BANANA: System.out.println(93+ " kcal"); break; } } }
그러나 한 클래스에서 같은 이름의 상수가 필요할 때가 있다.
기업이름도 추가해서 APPLE을 추가해야 한다면 컴파일 단계에서 오류가 생긴다. (컴파일 하는 시점에서 문제가 드러남)
해결법1 : FRUIT_, COMPANY_와 같이 접두사를 붙여줄 수 있다.
해결법2 : 인터페이스 사용
인터페스에서 필드를 선언하는 것은 public final static임을 함의한다.
그러나 문제는 FRUIT.APPLE과 COMPANY.APPLE을 비교하면 같은 것으로 나온다는 점.
interface FRUIT{ int APPLE = 1, PEACH = 2, BANANA = 3; } interface COMPANY{ int GOOGLE = 1, APPLE = 2, ORACLE = 3; } public class ConstantDemo { private final static int APPLE = 1; private final static int PEACH = 2; private final static int BANANA = 3; // 컴파일에서도 문제가 드러나지 않는다. if (FRUIT.APPLE == COMPANY.APPLE) { System.out.println("과일애플과 기업애플은 같습니다.") } public static void main(String[] args) { int type = FRUIT.APPLE; switch(type) { case FRUIT.APPLE: System.out.println(57+" kcal"); break; case FRUIT.PEACH: System.out.println(34+" kcal"); break; case FRUIT.BANANA: System.out.println(93+ " kcal"); break; } } }
해결법 3. 클래스 만들기
class Fruit{ public static final Fruit APPLE = new Fruit(); public static final Fruit PEACH = new Fruit(); public static final Fruit BANANA = new Fruit(); } class Company{ public static final Company APPLE = new Company(); public static final Company PEACH = new Company(); public static final Company BANANA = new Company(); }
이 경우 컴파일에서 문제가 드러나지 않던 비교 문제가 컴파일 오류로 드러난다.
if (Fruit.APPLE == Company.APPLE) { System.out.println("과일애플과 기업애플은 같습니다."); }
데이터 타입이 Fruit, Company로 다르므로 컴파일시 오류가 생긴다.(서로 비교가 불가능하다)
그러나 switch문 사용시 데이터 타입에 제한이 있어 switch문을 사용할 수 없다.
따라서 enum을 사용한다. (enum 또한 서로 다른 상수 그룹에 대한 비교를 컴파일 시점에서 차단할 수 있다)
(상수 그룹 별로 클래스를 만든 것의 효과를 갖는다.
- enum 사용법
enum Fruit{ APPLE, PEACH, BANANA; } enum Company{ GOOGLE, APPLE, ORACLE; } public class ConstantDemo { public static void main(String[] args) { Fruit type = Fruit.APPLE; // switch문은 type이 Fruit이라는 것을 알고 있으므로 case에 Fruit을 적지 않아도 된다. switch(type) { case APPLE: System.out.println(57+" kcal"); break; case PEACH: System.out.println(34+" kcal"); break; case BANANA: System.out.println(93+ " kcal"); break; } } }
enum은 사실상 클래스이기 때문에 생성자를 가질 수 있다.
(생성자를 밖에서 접근할 수는 없다)
싱글턴을 일반화한 형태
enum Fruit{ // 인자를 전달할 수 있다 APPLE("red"), PEACH("pink"), BANANA("yellow"); // enum안에 필드와 메서드가 모두 들어갈 수 있다. private String color; public String getColor() { return this.color; } // 상수를 열거하면 new Fruit(), 즉 Fruit가 인스턴스화 되면서 이를 만들기 위한 생성자가 호출된다. Fruit(String color){ // this는 인스턴스 System.out.println("Call Constructor " + this); this.color = color;// 전역변수 = 매개변수(지역변수-- 전역변수보다 우선순위가 높아서 그냥 color만 쓰면 가리킬 수 있다) } } enum Company{ GOOGLE, APPLE, ORACLE; } public class ConstantDemo { public static void main(String[] args) { Fruit type = Fruit.APPLE; // switch문은 type이 Fruit이라는 것을 알고 있으므로 case에 Fruit을 적지 않아도 된다. switch(type) { case APPLE: System.out.println(57+" kcal, color " + Fruit.APPLE.getColor()); break; case PEACH: System.out.println(34+" kcal, color " + Fruit.PEACH.getColor()); break; case BANANA: System.out.println(93+ " kcal, color " + Fruit.BANANA.getColor()); break; } } }
for (Fruit f : Fruit.values()) { System.out.println(f); }
public enum Operation { PLUS, MINUS, TIMES, DIVIDE; // 상수가 못하는 연산 수행 public duble apply(double x, double y){ switch(this) { case PLUS: return x+y; case MINUS: return x-y; case TIMES: return x*y; case DIVIDE: return x/y; } throw new AssertionError("알 수 없는 연산 + " + this); } }
- 출처 : 생활코딩