자바의 열거형에 대해 학습하세요.
- enum 정의하는 방법
- enum이 제공하는 메소드 (values()와 valueOf())
- java.lang.Enum
- EnumSet
enum 정의하는 방법
Enum이란?
- 열거형
- 서로 관련된 상수를 편리하게 선언하기 위한 것으로 상수를 여러 개 정의할 때 사용
- 정의된 것 이외의 값은 허용하지 않는다. (=허용 가능한 값들을 제한할 수 있다.)
- 리팩토링 시 내용 추가가 필요하더라도, Enum 코드 외에 수정할 필요가 없다.
- jdk 1.5부터 추가
enum 열거형이름 {상수명1, 상수명2, 상수명3, ...}
package enumex;
public class EnumTest {
enum Number {one, two, three, four}
public static void main(String[] args) {
EnumTest e = new EnumTest();
System.out.println(Number.two);
System.out.println(Number.two.ordinal()); // enum의 순서를 의미
}
}
자바 Enum의 특징
- Enum에 정의된 상수들은 해당 enum type의 객체이다.
enum Fruit { APPLE, PEACH, BANANA }
class Fruit {
public static final Fruit APPLE = new Fruit("APPLE");
public static final Fruit PEACH = new Fruit("PEACH");
public static final Fruit BANANA = new Fruit("BANANA");
private String name;
private Fruit(String name) {
this.name = name;
}
}
// 위와 아래는 같은 의미이다.
- 생성자와 메서드를 추가할 수 있다.
enum과 클래스를 정의하는 방법은 거의 비슷하지만 몇 가지 차이가 있다.
1. class 대신 enum 이라고 적는다.
2. 첫 줄에는 열거할 상수의 이름을 선언한다. (이름은 대문자가 관례이며 상수는 콤마로 구분, 제일 마지막 상수는 세미콜론을 붙여야 한다.)
3. enum의 생성자의 접근제어자는 private이므로 외부에서 상수를 추가할 수 없다.
4. 열거형의 멤버 중 하나를 호출하면, 열거된 모든 상수의 객체가 생성된다.
5. 상수 하나당 각각의 인스턴스가 만들어지며 모두 public static final 이다.
enum Fruit {
APPLE, PEACH, BANANA; // 열거할 상수의 이름 선언, 마지막에 ; 을 꼭 붙여야한다.
Fruit() {
System.out.println("생성자 호출 " + this.name());
}
}
public class EnumDemo {
public static void main(String[] args) {
Fruit apple = Fruit.APPLE;
// Fruit grape = new Fruit();
// 에러 발생. 열거형의 생성자의 접근제어자는 항상 private이다.
}
}
// 생성자 호출 APPLE
// 생성자 호출 PEACH
// 생성자 호출 BANANA
- 생성자를 이용하여 상수에 데이터를 추가할 수 있다.
package enumex;
public class EnumTest {
enum Number {
one(1), two(2), three(3), four(4);
private int i;
Number(int i) {
this.i = i;
}
public int getI() {
return i;
}
}
public static void main(String[] args) {
System.out.println(Number.two.getI());
}
}
// 2
- 추상 메서드를 선언하여 각 상수 별로 다르게 동작하는 코드를 구현할 수 있다.
enum을 상속받는 익명 클래스를 선언하는 것
package enumex;
public class EnumTest{
enum Number {
one(1){
@Override
public void getI() {
System.out.println("one : "+ Number.one.i);
}
},
two(2){
@Override
public void getI() {
System.out.println("two : "+ Number.two.i);
}
},
three(3){
@Override
public void getI() {
System.out.println("three : "+ Number.three.i);
}
},
four(4){
@Override
public void getI() {
System.out.println("four : "+ Number.four.i);
}
};
private int i;
Number(int i) {
this.i = i;
}
public void getI() {
}
}
public static void main(String[] args) {
Number.one.getI();
Number.two.getI();
Number.three.getI();
Number.four.getI();
}
}
// one : 1
// two : 2
// three : 3
// four : 4
- 상수 간의 비교가 가능하다.
== 비교 연산자 사용 가능
>, < 비교 연산자는 사용 불가 / compareTo()를 사용한다.
Direction dir;
if (dir == Direction.WEST) {
...
} else if (dir > Direction.WEST) {
// 에러. 열거형 상수에 비교연산자는 사용 불가능
} else if (dir.compareTo(Direction.WEST) > 0) {
// compareTo()는 가능
}
enum이 제공하는 메소드 (values()와 valueOf())
메서드 이름 | 설명 |
toString() | 해당 상수의 이름을 문자열로 반환 |
name() | 해당 상수의 이름을 문자열로 반화 |
compareTo() | 정렬의 기준을 위한 메서드 비교 대상보다 순서가 빠르면 -1, 같으면 0, 느리면 1을 반환 정렬 순서는 상수가 선언된 순서가 디폴트로 지정되어 있다. |
ordinal() | 상수의 선언 순서에 따른 인덱스(zero based)값을 반환 Enum 안에는 private final int ordinal; 이 정의되어 있고 이를 사용한다. |
valueOf() | 인자로 받은 이름과 같은 Enum값으로 반환 Direction d = Direction.valueOf("WEST"); Direction.WEST == Direction.valueOf("WEST"); // true 반환 |
values() | 선언된 모든 Enum값을 순서대로 배열에 담아서 반환 Direction[] arr = Direction.values(); |
package enumex;
public class EnumTest{
enum Number {
one(1){
@Override
public void getI() {
System.out.println("one : "+ Number.one.i);
}
},
two(1){
@Override
public void getI() {
System.out.println("two : "+ Number.two.i);
}
},
three(3){
@Override
public void getI() {
System.out.println("three : "+ Number.three.i);
}
},
four(4){
@Override
public void getI() {
System.out.println("four : "+ Number.four.i);
}
};
private int i;
Number(int i) {
this.i = i;
}
public void getI() {
}
}
public static void main(String[] args) {
Number[] values = Number.values();
for (Number value : values) {
System.out.println(value);
}
System.out.println();
System.out.println(Number.valueOf(Number.class, "one"));
}
}
// one
// two
// three
// four
// one
toString()과 name()의 차이
- toString()과 name()은 같은 값을 반환한다.
- name()은 final로 선언된 메서드로 오버라이딩이 불가능하다.
- toString()은 일반적인 Object 클래스의 메서드로 오버라이딩이 가능하다.
java.lang.Enum
- java.lang에 포함된 Enum은 모든 자바 열거형의 조상이다.
- 모든 열거형은 Enum 클래스를 상속받기 때문에 enum type은 별도의 상속을 받을 수 없다.
- Enum 클래스는 abstract 이기에 인스턴스를 생성할 수 없다.
- toString을 제외한 대부분의 메서드는 final로 선언되어 있기 때문에 오버라이딩 할 수 없다.
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
/**
* The name of this enum constant, as declared in the enum declaration.
* Most programmers should use the {@link #toString} method rather than
* accessing this field.
*/
private final String name;
/**
* Returns the name of this enum constant, exactly as declared in its
* enum declaration.
*
* <b>Most programmers should use the {@link #toString} method in
* preference to this one, as the toString method may return
* a more user-friendly name.</b> This method is designed primarily for
* use in specialized situations where correctness depends on getting the
* exact name, which will not vary from release to release.
*
* @return the name of this enum constant
*/
public final String name() {
return name;
}
...
EnumSet
set
- 데이터를 중복해서 저정할 수 없다.
- 저장 순서가 보장되지 않는다.
- 대표 클래스는 HashSet, TreeSet, LinkedHashSet 등이 있다.
- 공통적으로 사용하는 메서드는 add, iterator, size, remove, clear 등이 있다.
EnumSet
- Set 인터페이스를 기반으로 하면서 Enumeration type을 사용하는 방법
메서드 | 설명 |
allOf(Class elementType) | 인자로 들어온 enum을 그대로 enum set 생성 |
complementOf(EnumSet s) | 인자로 들어온 enum set에서 없는 요소들로만 다시 enum set 생성 |
of(E e1, E e2, E e3, E e4, E e5) | 초기값으로 지정한 값들로 enum set 생성 |
range(E from, E to) | 처음과 끝을 입력하면 그 사이에 있는 값들로 Enum set 생성 |
package enumex;
import java.util.EnumSet;
enum Alphabet {A, B, C, D, E}
public class EnumSetTest {
public static void main(String[] args) {
EnumSet<Alphabet> set1, set2, set3, set4;
set1 = EnumSet.allOf(Alphabet.class);
set2 = EnumSet.of(Alphabet.A, Alphabet.B, Alphabet.C, Alphabet.D, Alphabet.E);
set3 = EnumSet.complementOf(set1);
set4 = EnumSet.range(Alphabet.B,Alphabet.D);
System.out.println(set1);
System.out.println(set2);
System.out.println(set3);
System.out.println(set4);
}
}
// [A, B, C, D, E]
// [A, B, C, D, E]
// []
// [B, C, D]
EnumMap
- Key와 Value를 가지고 있다.
- Enum 상수는 이미 그 자체로 고유한 싱글턴 객체이므로 해싱처리를 해 줄 필요가 없다.
- 순서를 기억한다.
메서드 | 설명 |
put(K key, V value) | Key, Value 값을 받아 내부 배열에 저장한다. |
putAll(Map<? extends K, ? extends V>m | 이미 생성된 적 있는 Map 객체를 내부 배열에 저장한다. |
size() | Enummap의 Key와 Value 쌍의 갯수를 반환 |
get(Object key) | key를 통해 value의 값을 반환한다. |
containsKey(Object key) | EnumMap에 특정 key가 존재하는지 확인 후 boolean을 반환 |
containsValue(Object value) | EnumMap에 특정 value 값이 존재하는지 확인 후 boolean을 반환 |
replace(K key, V value) | 기존 key에 있던 value값을 바꾼다. |
replace(K keym, V oldValue, V newValue) | 안정성을 보장해주는 방법으로 key의 이전 value 값이 맞으면 현재값으로 변경해준다. |
package enumex;
import java.util.EnumMap;
enum Alphabet2 {A, B, C, D, E}
public class EnumMapTest {
public static void main(String[] args) {
EnumMap<Alphabet2,String> enumMap = new EnumMap<Alphabet2, String>(Alphabet2.class);
enumMap.put(Alphabet2.A,"AAA");
enumMap.put(Alphabet2.A,"AAA1");
enumMap.put(Alphabet2.B,"BBB");
enumMap.put(Alphabet2.C,"CCC");
enumMap.put(Alphabet2.D,"DDD");
System.out.println(enumMap.size()); // 사이즈 출력
System.out.println();
System.out.println(enumMap); // enumMap 출력
System.out.println();
System.out.println(enumMap.get(Alphabet2.C)); // 키값으로 값 출력
System.out.println();
System.out.println(enumMap.containsKey(Alphabet2.A)); // 키값을 포함하는지 확인
System.out.println();
System.out.println(enumMap.containsValue("AAA1")); // 값을 포함하는지 확인
System.out.println();
EnumMap<Alphabet2,String> enumMapTest = new EnumMap<Alphabet2, String>(Alphabet2.class);
enumMapTest.putAll(enumMap); // 정의된 enummap을 받음
System.out.println(enumMapTest);
System.out.println();
enumMapTest.replace(Alphabet2.A,"AAA1","AAA2"); // 특정 키 값이 주어진 값과 같으면 다른값으로 변경
System.out.println(enumMapTest.get(Alphabet2.A));
}
}
// 4
// {A=AAA1, B=BBB, C=CCC, D=DDD}
// CCC
// true
// true
// {A=AAA1, B=BBB, C=CCC, D=DDD}
// AAA2
'Back-end > java' 카테고리의 다른 글
스터디 13주차 - I/O (0) | 2021.07.07 |
---|---|
스터디 12주차 - 어노테이션 (0) | 2021.07.06 |
스터디 10주차 - 멀티쓰레드 프로그래밍 (0) | 2021.07.02 |
스터디 9주차 - 예외 처리 (0) | 2021.07.01 |
스터디 8주차 - 인터페이스 (0) | 2021.07.01 |