Skip to content

Latest commit

 

History

History
370 lines (278 loc) · 11.3 KB

File metadata and controls

370 lines (278 loc) · 11.3 KB

Enum에 대해서 설명해주세요.

Enum

목차

  1. enum이란?
  2. enum을 사용하여 상수 정의하기
  3. enum과 생성자
  4. enum JVM메모리 구조
  5. enum 메소드
  6. EnumSet
  7. enum 활용하기

1. enum이란?

  • enum(enumeration)은 관련이 있는 상수들의 집합이다.
  • enum은 자바 1.5버전부터 새롭게 추가되었다.
  • 자바에서는 final로 String과 같은 문자열이나 숫자들을 나타내는 기본 자료형의 값을 고정할 수 있는데, 그 고정된 값을 상수(constant)라고 한다.
  • 자바의 Enum은 상수 그룹을 정의하는 데 쓰이는 특수한 자바 클래스이다.
  • enum도 클래스고 객체이기 때문에, object클래스를 상속받고, object클래스의 메소드를 사용할 수 있다.
  • java의 컴파일러는 enum을 아래와 같은 형태로 바꾼다.
enum{
  
}

final class Week extends java.lang.Enum<Week>{ 
  
}
  • final클래스이므로 enum클래스를 다른 클래스가 상속받을 수 없다.
  • 자바는 다중 상속을 허용하지 않는데, java.lang.Enum을 상속받고 있으므로 다른 클래스를 상속받을 수 없다.
  • 인터페이스 구현은 가능하다.

2. enum을 사용하여 상수 정의하기

  • 열거형을 만들기 위해선 class, interface 대신 enum키워드를 사용하고 상수를 쉼표로 구분하면 된다.
enum Week {
  MONDAY,
  TUESDAY,
  WEDNESDAY,
  THURSDAY,
  FRIDAY,
  SATURDAY,
  SUNDAY;
}

→ 7개의 요일을 열거 타입으로 상수화 해 놓은 것이다. MONDAY부터 SUNDAY까지를 ‘열거 상수라고 한다. 열거 상수들은 대문자로 표기한다.

  • 위의 코드에서 선언된 열거 상수들은 모두 하나의 객체로 사용할 수 있다.

  • enum을 사용하지 않고 class를 이용하여 상수들을 정의하면 아래의 코드와 같다.

class 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();
  public static final Week SUNDAY = new Week();

→ class와 enum의 코드를 비교해 보면 enum을 사용하는 이유를 알 수 있다.

  1. 코드가 단순해지고 가독성이 좋아집니다.
  2. 인스턴스의 생성과 상속을 방지합니다.
  3. 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 나타낼 수 있습니다.

3. enum과 생성자

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

  • 생성자를 만들지 않으면 다른 클래스와 마찬가지로 디폴트 생성자가 만들어지지만, 차이점은 생성자의 접근 제어자가 private라는 것이다.

  • 위와 같은 이유로 enum클래스에서 선언한 상수들은 클래스가 로드될 때 하나의 인스턴스만 생성되어 사용된다.

  • enum클래스 내에서 까지도 new키워드로 인스턴스 생성이 불가능하고, newInstance(), clone() 등의 메소드도 사용불가하다.

  • enum클래스의 원소에 추가 속성 부여

enum Week {
  MONDAY("월요일"),
  TUESDAY("화요일"),
  WEDNESDAY("수요일"),
  THURSDAY("목요일"),
  FRIDAY("금요일"),
  SATURDAY("토요일"),
  SUNDAY("일요일");

  private final String name;

  Week(String name) {
    this.name = name;
  }

  public String getName(){
    return this.name;
  }
}

→ 추가 속성을 enum클래스의 필드에 설정해주고 생성자의 파라미터를 통해 초기화할 수 있다. getter메소드를 통해 해당 속성을 필요할 때에 사용할 수 있게 합니다.

4. enum과 JVM메모리 구조

스크린샷 2023-08-03 오후 9 46 50
Week today = Week.SUNDAY;
스크린샷 2023-08-03 오후 9 47 36

→ today는 스택 영역에 생성되고, today에 저장되는 값은 Week.SUNDAY 열거 상수가 참조하는 객체의 번지이다. 그래서 Week.SUNDAY와 today는 같은 객체를 참조한다.

today == Week.SUNDAY; //true

5. Enum 메소드

  • enum은 컴파일 타임에 Enum이라는 클래스를 상속한다. 즉, enum에서 사용할 수 있는 메소드는 Enum의 메소드이다.
  1. name()
  • 열거 객체가 가지고 있는 문자열을 반환하는데, 이때 문자열은 열거 객체를 선언할 때 명시한 상수 이름이다.
Week today = Week.MONDAY;
System.out.println(today.name()); //결과: MONDAY
  1. ordinal()
  • 해당 열거 객체가 열거 타입에서 몇 번째 순번인지 반환한다. 이때, 순번이란 열거 타입을 정의할 때 명시된 순서로 0부터 시작한다.
public enum Week {
    MONDAY, // 0
    TUESDAY, // 1
    WEDNESDAY, // 2
    THURSDAY, // 3
    FRIDAY, // 4
    SATURDAY, // 5
    SUNDAY; // 6
}
System.out.println(Week.MONDAY.ordinal()); // 0
System.out.println(Week.SUNDAY.ordinal()); // 6
  1. compareTo()
  • 두 열거 객체간의 순번을 비교하여 상대적 순번 차이를 반환하는 메소드이다.
System.out.println(Week.MONDAY.compareTo(Week.SUNDAY)); // -6
System.out.println(Week.SATURDAY.compareTo(Week.WEDNESDAY)); // 3
  1. valueOf()
  • 열거 객체의 상수명과 동일한 문자열을 입력받아, 일치하는 열거 객체를 반환한다. 외부에서 문자열을 입력받아 열거 객체로 변환할 때 사용한다.
Week today = Week.valueOf("WEDNESDAY");
System.out.println(today); // WEDNESDAY
  1. values()
  • enum에 선언된 모든 열거 객체를 순서대로 배열을 만든다.
for (Week day : Week.values()) {
    System.out.println(day);
}

/*
    MONDAY
    TUESDAY
    WEDNESDAY
    THURSDAY
    FRIDAY
    SATURDAY
    SUNDAY
*/

6. EnumSet

  • EnumSet은 enum클래스로 작동하기 위해 특화된 Set 컬렉션이다.
  • EnumSet은 Set인터페이스를 구현하고 AbstractSet을 상속하고 있다.
  • EnumSet을 사용할 때 고려할 사항
    • 열거형 값만 포함 할 수 있고, 모든 값은 동일한 열거형이어야 한다.
    • null을 추가할 수 없다.
    • 스레드에 안전하지 않으므로, 필요한 경우 외부에서 동기화한다.
enum Week {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY;
}
  • allOf()
EnumSet<Week> set = EnumSet.allOf(Week.class);

→ allOf()메소드를 통해 EnumSet을 만들 수 있다.

  • noneOf()
EnumSet<Week> set = EnumSet.noneOf(Week.class);

→ of()를 사용하면, 들어갈 요소를 직접 입력하여 EnumSet을 생성할 수 있다.

  • complementOf()
EnumSet<Week> set = EnumSet.complementOf(EnumSet.of(Week.BLACK,Week.BLUE));

→원하는 요소를 제거하고 EnumSet을 생성할 수 있다.

7. enum 활용하기

  1. 같은 의미이지만, 여러 개의 표현(타입)으로 나눠질 경우 Enum으로 묶어주면 명시적으로 활용이 가능하다.
public enum TableStatus {
	Y("1", true);
	N("0", false);
  private String tableValue1;
  private boolean tableValue2;

  TableStats(String tableValue1, boolean tableValue2) {
		this.tableValue1 = tableValue1;
		this.tableValue2 = tableValue2;
	}

  public String getTableValue1() {
		return this.tableValue1;
	}
  public String getTableValue2() {
		return this.tableValue2;
	}
}

→ (Y, “1”, true), (N, “0”, false)은 같은 의미를 지닌 값들을 묶어놓은 것이다. TableStatus의 enum타입을 전달받기만 한다면, 그에 맞춘 table1, table2값을 바로 얻을 수 있다.

  • @Getter를 이용하면 get메소드도 제거할 수 있어 매우 깔끔해진다.

  • Enum을 사용하지 않을 경우

public class Case {
   
    public String toTable1Value(String originValue) {
         if("Y".equals(originValue)){
            return 1;
         } else{
            return 0;
         }
    }

    public String toTable2Value(String originValue) {
         if("Y".equals(originValue)){
            return true;
         } else{
            return false;
         }
    }
}

→ 위 코드와 같이 같은 의미를 지니지만 다른 타입의 값을 원할 경우마다 메소드를 만들어 if문을 사용해 주어야 한다. 그러면 너무 불필요한 코드량이 많아지기 때문에 enum을 사용하는 것이 훨씬 효율적입니다.

  1. 비즈니스 로직 자체를 종류별로 타입화
  • Java8부터 도입된 함수형 인터페이스를 통해서 조금 더 깔끔한 비즈니스 로직 처리를 기대할 수 있다.
public enum CalculateType {
	CALCULATE_A(value->value),
	CALCULATE_B(value->value*2);
  
	Function<Long,Long> expression;
  CalculateType(Function<Long,Long> expression) { this.expression = expression; }
	
	public long calculate(long value) {
		return expression.apply(value);
	}
}

CALCULATE_A.calculate(2000);

[Reference]

https://www.nextree.co.kr/p11686/

https://hudi.blog/java-enum/

https://techblog.woowahan.com/2527/

https://scshim.tistory.com/253

https://cokes.tistory.com/93

질문 답변

1) Object 클래스의 메소드에는 무엇이 있나요?

  • clone()
    • 객체의 복사본을 만들어 리턴한다.
  • equals()
    • 현재 객체와 매개 변수로 넘겨 받은 객체가 같은지 확인한다. 같으면 true를 다르면 false를 리턴한다.
  • finalize()
    • 현재 객체가 더 이상 쓸모가 없어졌을 때 가비지 컬렉터에 의해서 이 메소드가 호출된다.
  • getClass()
    • 현재 객체의 Class클래스의 객체를 리턴한다.
  • hashCode()
    • 객체에 대한 해시코드 값을 리턴한다. 해시코드란 16진수 객체 메모리의 주소를 말한다.
  • toString()
    • 객체를 문자열로 표현하는 값을 리턴한다.

스레드 처리를 위한 메소드

  • notify()
    • 모니터에 대기하고 있는 단일 스레드를 깨운다.
  • notifyAll()
    • 모니터에 대기하고 있는 모든 스레드를 깨운다.
  • wait()
    • 다른 스레드가 현재 객체에 대한 notify()메소드나 notifyAll()메소드를 호출할 때까지 현재 스레드가 대기하고 있도록 한다.

2) 내부적으로 어떤 식으로 데이터를 저장하고 있나?

정수 값으로 매핑

예를 들어, 첫 번째 상수는 0, 두 번째 상수는 1, 세 번째 상수는 2와 같이 순차적으로 매핑될 수 있습니다.

enum Weekday {
    MONDAY,    // 0
    TUESDAY,   // 1
    WEDNESDAY, // 2
}

즉, 대부분의 언어에서 Enum 클래스는 내부적으로 정수 값을 사용하여 각 상수를 나타내며, 이 값들은 메모리에 해당 정수 값으로 저장됩니다

protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

→ Enum클래스 인스턴스를 만들어 낼 때 생성자에서 열거 상수의 이름(name)과 순서(ordinal)를 초기화하고 내부적으로 저장합니다.

3) enum 클래스 필드에 추가할 수 있는 속성에는 어떤 것들이 있나요?

  • enum 클래스 필드에 추가할 수 있는 속성에는 제한이 없다.