ENUM
- 프로그래밍 언어/자바
- 2021. 1. 24. 18:26
enum : 열거형이라고 불리며,
서로 연관된 상수들의 집합이라고 불린다.
원래 자바에는 enum클래스가 존재하지 않았지만, JDK1.5에 추가되었다고 한다.
C언어 같은 언어에서는 enum클래스의 역할은 단순히 상수들의 집합으로 사용되었지만,
자바는 타입까지 비교가 가능하다.
enum을 만드는 방법
기본적으로
public enum Language {
C, JAVA, KOTLIN, JAVASCRIPT
}
이렇게 만들면 된다.
이들은 왼쪽부터 오른쪽으로 0번부터 3번으로 측정된다.
System.out.println(Language.C.ordinal());
System.out.println(Language.JAVA.ordinal());
System.out.println(Language.KOTLIN.ordinal());
System.out.println(Language.JAVASCRIPT.ordinal());
ordinal() : enum의 순서를 의미한다.
만약,
public enum Language {
JAVA, KOTLIN, JAVASCRIPT,C
}
라면 순서가 바뀌기 때문에 JPA를 사용할때는 주의해야된다.(JPA는 어노테이션으로 지정하지만 말이다.)
enum에서 값을 꺼내오는 방법
값을 꺼내 오는 방법은 총 3가지가 존재한다.
1.System.out.println(Language.C);
2.System.out.println(Language.valueOf("JAVA"));
3.System.out.println(Enum.valueOf(Language.class,"JAVASCRIPT"));
사실 한 가지더 존재한다.
System.out.println(Language.KOTLIN.name());
뒤에 name을 붙일 수 도 있는데,
name()은 현재 enum의 값의 이름을 뜻한다.
신기하게도 name을 생략하여도 enum의 이름이 등장하는 것을 알 수 있다.
이는 내부적으로 toString()이 name()과 같다는 뜻인 것 같다.
위 enum클래스는 이런식으로 작성할 수있다.
public static final LanguageClass C = new LanguageClass("C");
public static final LanguageClass JAVA = new LanguageClass("JAVA");
public static final LanguageClass KOTLIN = new LanguageClass("KOTLIN");
public static final LanguageClass JAVASCRIPT = new LanguageClass("JAVASCRIPT");
private String name;
public LanguageClass(String name) {
this.name = name;
}
생성자 추가
여기서 생성자를 추가하면 어떻게 될까?
아마, 이런식으로 수정되지 않을까?
public static final LanguageClass C = new LanguageClass("C",100);
public static final LanguageClass JAVA = new LanguageClass("JAVA",200);
public static final LanguageClass KOTLIN = new LanguageClass("KOTLIN",300);
public static final LanguageClass JAVASCRIPT = new LanguageClass("JAVASCRIPT",400);
enum클래스와 위 클래스를 비교해보면 차이점이 하나 존재하는데,
enum클래스는 변수명만 작성된다는것을 알 수 있다.
그렇다는 이야기는
C(100), JAVA(200), KOTLIN(300), JAVASCRIPT(400);
private int size;
Language(int size) {
this.size = size;
}
이렇게 수정할 수 있다.
메소드 추가
생성자를 추가했으니, 이제 메소드를 추가해보자,
public void print(int number) {
System.out.println(number);
}
간단히 number을 입력받아서 프린트하는것을 만들었다. 물론 이렇게 만들면 큰 의미는 없다.
왜나햐면 그냥 사용해도 무방하기 때문이다.
하지만 내가 하고 싶은 것은 오버라이딩이다.
enum은 각 클래스를 인스턴스화 시킨 것이기 때문에 오버라이딩이 되지 않을까?
C(100) {
@Override
public void print(int number) {
System.out.println(number+100);
}
}, JAVA(200) {
@Override
public void print(int number) {
System.out.println(number+200);
}
}, KOTLIN(300) {
@Override
public void print(int number) {
System.out.println(number+300);
}
}, JAVASCRIPT(400) {
@Override
public void print(int number) {
System.out.println(number+400);
}
};
역시 내 예상되로 오버라이딩이 된다.
이제 프린트라는 메소드는 서로다른 값을 프린트하게 바꼈다.
enum에서 제공되는 메소드
위에서 알아본 enum메소드에 추가해서 몇 가지를 더 알아보자.
ordinal() : enum의 순서
name() : 각 요소들의 이름(toString에 기본으로 작성되어있다.)
valueOf() : 문자열로 enum요소의 이름을 찾아서 요소의 이름을 리턴한다.
values() : 모든 enum의 요소들을 배열로 만들어준다.
Language[] values = Language.values();
for (Language value : values) {
System.out.println(value);
}
이들도 Object의 자손이 기때문에 Object의 메소드도 사용이 가능하다.
conpareTo() : == 비교는 가능하지만, <,>,<=,=>는 불가능하다. 만약, 비교를 하고 싶다면 compareTo를 이용하면 된다.
if (Language.JAVA == Language.C) {
}
if (Language.JAVA.compareTo(Language.C) == -1) {
System.out.println("java 가 더 작다.");
} else {
System.out.println("java 가 더 크다");
}
동일 => == 또는 a.compareTo(b) == 0
a가 b보다 작다 => a.compareTo(b) == 1
a가 b보다 크다 a.compareTo(b) == -1
java.lang.Enum
모든 enum클래스는 위 클래스의 자손이다.
우리가 만든 Language를 제외하고도 수 많은 enum이 정의 되있다는 것을 알 수 있다.
참고로 O는 구현체를 뜻한다.
지금까지 enum(Language), (LanguageClass)?를 만들어봤다.
이번에는 java.lang.enum을 상속받아서 새로운 enum을 만들어보자.
제일먼저 enum클래스를 흉내낸 것 부터
public abstract class MyEnum<T extends MyEnum<T>> implements Comparable<T>{
private int ordinal;
private String name;
public int ordinal() {
return ordinal;
}
private int size;
public MyEnum(String name, int size) {
this.name = name;
this.size = size;
ordinal++;
}
@Override
public int compareTo(T t) {
return ordinal - t.ordinal();
}
@Override
public String toString() {
return name;
}
}
public class LanguageEnum extends MyEnum {
public static final LanguageClass C = new LanguageClass("C",100);
public static final LanguageClass JAVA = new LanguageClass("JAVA",200);
public static final LanguageClass KOTLIN = new LanguageClass("KOTLIN",300);
public static final LanguageClass JAVASCRIPT = new LanguageClass("JAVASCRIPT",400);
public LanguageEnum(String name, int size) {
super(name, size);
}
}
점점
public class LanguageClass {
public static final LanguageClass C = new LanguageClass("C",100);
public static final LanguageClass JAVA = new LanguageClass("JAVA",200);
public static final LanguageClass KOTLIN = new LanguageClass("KOTLIN",300);
public static final LanguageClass JAVASCRIPT = new LanguageClass("JAVASCRIPT",400);
private String name;
private int size;
public LanguageClass(String name,int size) {
this.name = name;
this.size = size;
}
@Override
public String toString() {
return name;
}
}
줄어든다.
public enum Language {
C(100), JAVA(200), KOTLIN(300), JAVASCRIPT(400);
private int size;
Language(int size) {
this.size = size;
}
}
많이 줄었다는 것을 확인할 수 있다.
그렇다면 이들의 바이트 코드는 같을까? 다를까? 아무래도 enum을 직접 구현한것이기 때문에 다르지 않을까 예상해본다.
이건 역순으로 해보자.
public final enum study/whiteship/homework11/Language extends java/lang/Enum {
static <clinit>()V
L0
LINENUMBER 4 L0
NEW study/whiteship/homework11/Language
DUP
LDC "C"
ICONST_0
BIPUSH 100
INVOKESPECIAL study/whiteship/homework11/Language.<init> (Ljava/lang/String;II)V
PUTSTATIC study/whiteship/homework11/Language.C : Lstudy/whiteship/homework11/Language;
NEW study/whiteship/homework11/Language
DUP
LDC "JAVA"
ICONST_1
SIPUSH 200
INVOKESPECIAL study/whiteship/homework11/Language.<init> (Ljava/lang/String;II)V
PUTSTATIC study/whiteship/homework11/Language.JAVA : Lstudy/whiteship/homework11/Language;
NEW study/whiteship/homework11/Language
DUP
LDC "KOTLIN"
ICONST_2
SIPUSH 300
INVOKESPECIAL study/whiteship/homework11/Language.<init> (Ljava/lang/String;II)V
PUTSTATIC study/whiteship/homework11/Language.KOTLIN : Lstudy/whiteship/homework11/Language;
NEW study/whiteship/homework11/Language
DUP
LDC "JAVASCRIPT"
ICONST_3
SIPUSH 400
INVOKESPECIAL study/whiteship/homework11/Language.<init> (Ljava/lang/String;II)V
PUTSTATIC study/whiteship/homework11/Language.JAVASCRIPT : Lstudy/whiteship/homework11/Language;
L1
LINENUMBER 3 L1
ICONST_4
ANEWARRAY study/whiteship/homework11/Language
DUP
ICONST_0
GETSTATIC study/whiteship/homework11/Language.C : Lstudy/whiteship/homework11/Language;
AASTORE
DUP
ICONST_1
GETSTATIC study/whiteship/homework11/Language.JAVA : Lstudy/whiteship/homework11/Language;
AASTORE
DUP
ICONST_2
GETSTATIC study/whiteship/homework11/Language.KOTLIN : Lstudy/whiteship/homework11/Language;
AASTORE
DUP
ICONST_3
GETSTATIC study/whiteship/homework11/Language.JAVASCRIPT : Lstudy/whiteship/homework11/Language;
AASTORE
PUTSTATIC study/whiteship/homework11/Language.$VALUES : [Lstudy/whiteship/homework11/Language;
RETURN
MAXSTACK = 5
MAXLOCALS = 0
java에서 제공한 enum
public class study/whiteship/homework11/LanguageClass {
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 4 L0
NEW study/whiteship/homework11/LanguageClass
DUP
LDC "C"
BIPUSH 100
INVOKESPECIAL study/whiteship/homework11/LanguageClass.<init> (Ljava/lang/String;I)V
PUTSTATIC study/whiteship/homework11/LanguageClass.C : Lstudy/whiteship/homework11/LanguageClass;
L1
LINENUMBER 5 L1
NEW study/whiteship/homework11/LanguageClass
DUP
LDC "JAVA"
SIPUSH 200
INVOKESPECIAL study/whiteship/homework11/LanguageClass.<init> (Ljava/lang/String;I)V
PUTSTATIC study/whiteship/homework11/LanguageClass.JAVA : Lstudy/whiteship/homework11/LanguageClass;
L2
LINENUMBER 6 L2
NEW study/whiteship/homework11/LanguageClass
DUP
LDC "KOTLIN"
SIPUSH 300
INVOKESPECIAL study/whiteship/homework11/LanguageClass.<init> (Ljava/lang/String;I)V
PUTSTATIC study/whiteship/homework11/LanguageClass.KOTLIN : Lstudy/whiteship/homework11/LanguageClass;
L3
LINENUMBER 7 L3
NEW study/whiteship/homework11/LanguageClass
DUP
LDC "JAVASCRIPT"
SIPUSH 400
INVOKESPECIAL study/whiteship/homework11/LanguageClass.<init> (Ljava/lang/String;I)V
PUTSTATIC study/whiteship/homework11/LanguageClass.JAVASCRIPT : Lstudy/whiteship/homework11/LanguageClass;
RETURN
MAXSTACK = 4
MAXLOCALS = 0
상수만 저장된 클래스
public class study/whiteship/homework11/LanguageEnum extends study/whiteship/homework11/MyEnum {
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 4 L0
NEW study/whiteship/homework11/LanguageClass
DUP
LDC "C"
BIPUSH 100
INVOKESPECIAL study/whiteship/homework11/LanguageClass.<init> (Ljava/lang/String;I)V
PUTSTATIC study/whiteship/homework11/LanguageEnum.C : Lstudy/whiteship/homework11/LanguageClass;
L1
LINENUMBER 5 L1
NEW study/whiteship/homework11/LanguageClass
DUP
LDC "JAVA"
SIPUSH 200
INVOKESPECIAL study/whiteship/homework11/LanguageClass.<init> (Ljava/lang/String;I)V
PUTSTATIC study/whiteship/homework11/LanguageEnum.JAVA : Lstudy/whiteship/homework11/LanguageClass;
L2
LINENUMBER 6 L2
NEW study/whiteship/homework11/LanguageClass
DUP
LDC "KOTLIN"
SIPUSH 300
INVOKESPECIAL study/whiteship/homework11/LanguageClass.<init> (Ljava/lang/String;I)V
PUTSTATIC study/whiteship/homework11/LanguageEnum.KOTLIN : Lstudy/whiteship/homework11/LanguageClass;
L3
LINENUMBER 7 L3
NEW study/whiteship/homework11/LanguageClass
DUP
LDC "JAVASCRIPT"
SIPUSH 400
INVOKESPECIAL study/whiteship/homework11/LanguageClass.<init> (Ljava/lang/String;I)V
PUTSTATIC study/whiteship/homework11/LanguageEnum.JAVASCRIPT : Lstudy/whiteship/homework11/LanguageClass;
RETURN
MAXSTACK = 4
MAXLOCALS = 0
}
enum과 최대한 비슷하게 만든 클래스
놀랍게도 3개가 거의 비슷하다는 것을 알 수 있었다.
다만, 자바에서 제공되는 enum클래스는 다른 클래스보다 바이트코드의 길이가 길다는것을 알 수 있었습니다.
+) EnumSet
이것을 이용하면 Enum을 가지고 Set자료구조를 만들 수 있다.
중복 제외.
allOf : enum에 정의된 정보를 모두 추가할 수 있다.
EnumSet.allOf(Language.class);
noneOf : 아무것도 추가하지 않는다.
of : 요소를 직접넣을 수 있다.
EnumSet<Language> languages = EnumSet.of(Language.C, Language.JAVA);
이넘타입들은 각자 클래스로 구현되는느낌이다. ㅎ;
출처 : 자바의 정석