Java/라이브스터디

Enum

학습목표

  • enum 정의하는 방법
  • enum이 제공하는 메소드 (values()와 valueOf())
  • java.lang.Enum
  • EnumSet

 

Enum

서로 관련이 있으면서 의미가 있는 상수들의 집합.

정의 방법.

[접근 지시자] enum [Enum 타입]{
    /* enum 변수목록 */
}

/* 예시 */
public enum Months{
    January, February, March,
    April, May, June,
    July, August, September,
    October, November, December;
}

자바에서의 Enum은 기본적으로 클래스입니다.
클래스의 특징인 상속은 불가능하지만 메소드와 필드, 생성자를 사용하는게 가능합니다.

 

Enum을 배우면서 좀 신기하다 싶었던 것 들을 되짚어봅시다!

 

Enum 요소 각각은 무엇일까?

public enum Direction {
    North,
    West,
    South,
    East;

    Direction(){
        System.out.println("I'm Direction!!!");
    }
}
public class EnumTest{
    public static void main(String[] args) {
        for (Direction value : Direction.values()) {
            System.out.println(value);
        }
    }
}

일단 전 위의 예제를 보고 직접 Direction 객체를 생성한 적이 없으니 생성자는 호출되지 않을 것이라고 생각했습니다

.

하지만 출력 결과를 확인해보니 다음과 같았습니다.

I'm Direction!!!
I'm Direction!!!
I'm Direction!!!
I'm Direction!!!
North
West
South
East

변수들이 각각 Enum 타입의 생성자를 호출하는 것을 확인할 수 있었습니다.

추가적으로 파라미터를 가진 생성자는 어떻게 처리되는지가 궁금해서 파라미터를 가진 생성자 또한 선언해봤습니다.



public enum Direction {
    North,
    West,
    South(10),
    East(20);

    Direction(){
        System.out.println("I'm Direction!!!");
    }

    Direction(int a){
        System.out.println(a);
    }
}
public class EnumTest{
    public static void main(String[] args) {
        for (Direction value : Direction.values()) {
            System.out.println(value);
        }
    }
}
I'm Direction!!!
I'm Direction!!!
10
20
North
West
South
East

파라미터를 가진 Enum요소는 해당하는 생성자를 호출하는 것을 확인했습니다.

 

즉, 여기까지만 보면 Enum의 각 요소는 객체라는 것으로 느껴졌으며, 풀어서 말해보자면

Direction의 기능을 할 수 있는 내가 원하는 이름의 객체

정도로 느껴졌습니다.



객체가 맞는걸까?

앞선 결과를 가지고 이게 객체가 맞다는 판단하에 어떤게 되는지 확인해 봤습니다.

 

public enum Direction {
    North{
        public void show(){
            System.out.println("Inner Method");
        }
    },
    West,
    South(10),
    East(20);

    private final int value;

    Direction(){
        this.value = 0;
        System.out.println("I'm Direction!!!");
    }

    Direction(int value){
        this.value = value;
    }
}

첫번째로 알아낸건 Enum 변수 내에서 메소드의 선언이 가능하다는 사실입니다.
일단 선언이 가능하다는 사실은 알아냈으니 이번엔 저 메소드를 호출하는 방법을 알아야했다.

 

 

1. 생성과 동시에 호출되는건가?

public class EnumTest{
    public static void main(String[] args) {
        System.out.println(Direction.North);
    }
}

== 출력 결과 ==
I'm Direction!!!
I'm Direction!!!
North

생성과 동시에 호출되는 것은 아닌걸로 보인다.. ㅠ

대신 건진게 있는데 Enum 변수 중에서 동일한 Enum 타입의 생성자의 틀대로 만들어놓은 변수 모두가 해당 생성자를 호출한다는 사실이었다.



2. 이름.메소드() 로 호출되는건가?

public class EnumTest{
    public static void main(String[] args) {
    	Direction.North.show();
    }
}

그냥 빨간줄만 그이는 모습을 확인할 수 있었다ㅠㅠ

 

 

3. 재정의에 형태로 만들면 어떨까?

public enum Direction {
    North{
        public void show(){
            System.out.println("Inner Method");
        }
    },
    West,
    South(10),
    East(20);

    private final int value;

    Direction(){
        this.value = 0;
        System.out.println("I'm Direction!!!");
    }

    Direction(int value){
        this.value = value;
    }

    public void show(){

    }
}
public class EnumTest{
    public static void main(String[] args) {
        Direction.North.show();
    }
}

드디어 저 메소드를 호출하는 것이 성공했다!!


Intellij에서도 해당 메소드가 재정의된다고 좌측에 표시해주는 모습이 확인되었습니다.

 

 

 

 

그래서 Enum 요소 각각이 뭔데..?

모든 Enum은 java.lang.Enum를 암시적으로 상속한다. 자바에서의 다중 상속은 불가능하기 때문에 Enum은 다른 것을 상속할 수 없다.

출처 : https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

public class Direction extends Enum

위의 문구를 통해 enum은 결국 내부적으로 이런 형태일 것입니다.

 

 

Classes cannot directly extend 'java.lang.Enum'

물론 Intellij에서 위와 같이 클래스를 정의하려고하면 위 문구와 함께 제지당합니다.

암튼 enum이 java.lang.Enum를 상속하는 클래스라는 사실은 알았고.. enum의 각 요소들은 과연 객체일까요?



public class Direction{
    public static final Direction North = new Direction(){
        @Override
        public void show() {
            System.out.println("Inner");
        }
    };
    public static final Direction West = new Direction();
    public static final Direction South = new Direction(10);
    public static final Direction East = new Direction(20);

    private final int value;

    private Direction(){
        this.value = 0;
        System.out.println("I'm Direction!!!");
    }

    private Direction(int value){
        this.value = value;
    }

    public void show(){

    }
}
public class EnumTest{
    public static void main(String[] args) {
        System.out.println(Direction.North);
        Direction.North.show();
    }
}
I'm Direction!!!
I'm Direction!!!
PlayGround.Direction$1@66a29884
Inner

enum을 사용하지 않고 비슷한 동작을 하는 클래스를 만들어봤습니다.

 

클래스내의 각 객체 그 자체를 불렀을 때, 이름을 반환하는 것 말고는 거의 동일하게 동작하는 것을 확인할 수 있었기 때문에,  enum 은 객체가 생성된다고 볼 수 있다고 생각합니다.

 

 

 



enum이 쓸 수 있는 메소드는 뭐가있을까

앞에서 enum으로 선언된 클래스는 내부적으로 java.lang.Enum을 상속한다는 사실을 배웠습니다.

그럼 이제 enum으로 선언된 Enum 타입이 사용할 수 있는 메소드를 알아봅시다!

 

 



valueOf()

public class EnumTest{
    public static void main(String[] args) {
        System.out.println(Enum.valueOf(Direction.class, "North"));
        System.out.println(Direction.valueOf("North"));
    }
}

public enum Direction {
    North,
    West,
    South,
    East;
}

== 출력 결과 ==
North
North

Enum 타입에 해당하는 Enum변수를 반환하는 메소드

반환되는 값은 Enum 변수이다.

 

 



values()

public class EnumTest{
    public static void main(String[] args) {
        System.out.println(Direction.values());
        for (Direction value : Direction.values()) {
            System.out.println(value);
        }
    }
}
public enum Direction {
    North,
    West,
    South,
    East;
}

== 출력 결과 ==
[LPlayGround.Direction;@1e80bfe8
North
West
South
East

Enum 타입에 해당하는 모든 Enum 변수의 선언된 순서에 따른 참조배열을 반환하는 메소드

구현한 Enum 타입을 가지고 호출해야 된다.

 

 



ordinal()

public class EnumTest{
    public static void main(String[] args) {
        System.out.println(Direction.North.ordinal());
        System.out.println(Direction.West.ordinal());
        System.out.println(Direction.South.ordinal());
        System.out.println(Direction.East.ordinal());
    }
}

public enum Direction {
    North,
    West,
    South,
    East;
}


== 출력 결과 ==
0
1
2
3

선언된 순서에 따라 인덱스를 0부터 출력해주는 메소드

 

 



name() , toString()

public class EnumTest{
    public static void main(String[] args) {
        System.out.println(Direction.North.name());
    }
}

public enum Direction {
    North,
    West,
    South,
    East;
}

== 출력 결과 ==
North

Enum 변수값을 문자열로 반환해주는 메소드



java.lang.Enum

모든 enum이 내부적으로 상속하고있는 클래스
모든 enum이 이 클래스를 상속하기 때문에 enum은 클래스의 상속이 불가능하다.

interface의 상속은 가능하다!

EnumSet

EnumSet은 Java Collections Framework의 멤버중 하나인 추상클래스이다.

기본적으로 Set은 집합이기 때문에 중복되는 값이 내부에 있을 수 없다.

 

public class EnumTest{

    public static void main(String[] args) {
        EnumSet<Direction> NotEmpty = EnumSet.allOf(Direction.class);
        EnumSet<Direction> Empty = EnumSet.noneOf(Direction.class);

        System.out.println(NotEmpty);
        System.out.println(Empty);
    }
}

== 출력 결과 ==
[North, West, South, East]
[]

추상클래스이기 때문에 객체의 생성은 불가능하며 위와 같은 방법으로 선언한다.

 

 

 

 

add()와 remove()

System.out.println(NotEmpty);
NotEmpty.remove(Direction.North);
System.out.println(NotEmpty);
NotEmpty.add(Direction.North);
System.out.println(NotEmpty);

== 출력 결과 == 
[North, West, South, East]
[West, South, East]
[North, West, South, East]

EnumSet내의 요소의 삭제와 추가를 담당하는 메소드이다.

 

 

 

size()

현재 EnumSet의 원소개수를 반환한다.

 

 

 

copyOf()

EnumSet<Direction> NotEmpty = EnumSet.allOf(Direction.class);
EnumSet<Direction> Copy = EnumSet.copyOf(NotEmpty);

System.out.println(Copy);

== 출력 결과 == 
[North, West, South, East]

다른 EnumSet 또는 Collection을 복사한다.

 

 

 

contains()

해당하는 Enum타입의 변수가 Set 안에 있는지의 여부를 반환한다. (true | false)

 

 

 

of()

EnumSet<Direction> TEST = EnumSet.of(Direction.North, Direction.East);
System.out.println(TEST);

== 출력 결과 ==
[North, East]

해당하는 요소로 만들어진 EnumSet을 반환한다.

 

 

 

range()

EnumSet<Direction> TEST = EnumSet.range(Direction.West, Direction.East);
System.out.println(TEST);

== 출력 결과 ==
[West, South, East]

Enum 타입의 시작하는 인덱스부터 끝 인덱스까지의 모든 Enum 변수로 이루어진 EnumSet을 반환한다.

 

 

 

값에 접근

EnumSet<Direction> NotEmpty = EnumSet.allOf(Direction.class);

for (Direction direction : NotEmpty) {
    System.out.println(direction);
}

== 출력 결과 == 

North
West
South
East

향상된 for문을 이용하여 EnumSet내의 값에 대한 접근이 가능하다



EnumMap

public class EnumTest{
    public static void main(String[] args) {
        EnumMap<Direction, Integer> EM = new EnumMap<>(Direction.class);
        EM.put(Direction.North, 4);
        EM.put(Direction.South, 3);
        System.out.println(EM.get(Direction.North));
        System.out.println(EM.get(Direction.South));
    }
}
=== 출력 결과 ===

4
3

값에 대한 식별자를 지닌 자료구조 Enum 버전
추상클래스가 아니기때문에 객체 생성이 가능할 것이며, EnumSet과 함께 Java Collections Framework의 멤버중 하나라고 합니다.

 

 

put()과 get()

public class EnumTest{
    public static void main(String[] args) {
        EnumMap<Direction, Integer> EM = new EnumMap<>(Direction.class);
        EM.put(Direction.North, 1);
        System.out.println(EM);
        EM.put(Direction.West, 2);
        System.out.println(EM);
        EM.put(Direction.South, 3);
        System.out.println(EM);
        EM.put(Direction.East, 4);
        System.out.println(EM);
    }
}

== 출력 결과 ==

{North=1}
{North=1, West=2}
{North=1, West=2, South=3}
{North=1, West=2, South=3, East=4}

put()의 경우 EnumMap에 key값과 value 쌍을 저장하는 기능을 가지고 있습니다.

 

public class EnumTest{
    public static void main(String[] args) {
        EnumMap<Direction, Integer> EM = new EnumMap<>(Direction.class);
        EM.put(Direction.North, 1);
        EM.put(Direction.West, 2);
        EM.put(Direction.South, 3);
        EM.put(Direction.East, 4);

        System.out.println(EM.get(Direction.North));
        System.out.println(EM.get(Direction.East));
        System.out.println(EM.get(Direction.South));
        System.out.println(EM.get(Direction.West));
    }
}

== 출력 결과 ==

1
4
3
2

get()은 key값을 파라미터로 받아 해당 key값에 매칭되는 value를 반환합니다.

 

 

 

keySet()

public class EnumTest{
    public static void main(String[] args) {
        EnumMap<Direction, Integer> EM = new EnumMap<>(Direction.class);
        EM.put(Direction.North, 1);
        EM.put(Direction.West, 2);
        EM.put(Direction.South, 3);
        EM.put(Direction.East, 4);

        System.out.println(EM);

        for (Direction direction : EM.keySet()) {
            System.out.println(direction);
        }

    }
}

== 출력 결과 ==

{North=1, West=2, South=3, East=4}
North
West
South
East

Map에 저장된 모든 key값을 Set으로 반환해주는 메소드.

 

 

 

values()

public class EnumTest{
    public static void main(String[] args) {
        EnumMap<Direction, Integer> EM = new EnumMap<>(Direction.class);
        EM.put(Direction.North, 1);
        EM.put(Direction.West, 2);
        EM.put(Direction.South, 3);
        EM.put(Direction.East, 4);

        System.out.println(EM);

        for (Integer value : EM.values()) {
            System.out.println(value);
        }

    }
}

== 출력 결과 == 

{North=1, West=2, South=3, East=4}
1
2
3
4

Map에 저장된 value값만 Set으로 반환해주는 메소드.

 

 

 

entrySet()

public class EnumTest{
    public static void main(String[] args) {
        EnumMap<Direction, Integer> EM = new EnumMap<>(Direction.class);
        EM.put(Direction.North, 1);
        EM.put(Direction.West, 2);
        EM.put(Direction.South, 3);
        EM.put(Direction.East, 4);

        System.out.println(EM);

        Set<Map.Entry<Direction, Integer>> Ret = EM.entrySet();


        for (Map.Entry<Direction, Integer> directionIntegerEntry : Ret) {
            System.out.println("Key값 : " + directionIntegerEntry.getKey() + " / Value 값 : " + directionIntegerEntry.getValue());
        }

    }
}

== 출력 결과 ==
{North=1, West=2, South=3, East=4}
Key값 : North / Value 값 : 1
Key값 : West / Value 값 : 2
Key값 : South / Value 값 : 3
Key값 : East / Value 값 : 4

EnumMap을 Set<Map.Entry<key, value>>타입으로 반환해준다.

key와 value가 매핑된 상태로 저장된 Set이라고 생각하면 될 것 같다.

향상된 for문으로 값에 접근할 수 있으며, 현재 key값과 value값을 모두 접근할 수 있다.

 

 

 

containsKey(), containsValue()

EnumMap안에 key값이나 value값이 들어있는지 확인하는 메소드.

내부에 존재하면 true, 없으면 false를 반환한다.

 

 

 

clear()

EnumMap을 비우는 메소드.

 

 

 

출처 

- https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Enum.html

 

Enum (Java SE 15 & JDK 15)

Type Parameters: E - The enum type subclass All Implemented Interfaces: Serializable, Comparable , Constable public abstract class Enum > extends Object implements Constable, Comparable , Serializable This is the common base class of all Java language enum

docs.oracle.com

- https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html