KSCOLD LogoKSCOLD
Blog
Feed
Product
Admin Night
Vault
Guestbook
Info

Vault 목록

인터페이스 상수

연결된 노트와 함께 읽기

인터페이스 상수

2024년 1월 26일
  • 인터페이스(Interface)는 반드시 추상 메서드(Abstract Method)만 선언할 수 있는 것이 아니다.
  • 인터페이스 내에서도 상수를 선언할 수 있는데, 인터페이스의 멤버는 public static final 속성을 생략할 수 있는 특징을 이용하여 코드를 조금 더 간결하게 작성할 수 있게 된다.

Enum 기본 문법

  • 열거 타입은 상수 데이터들의 집합이라고 하였다. 따라서 아래와 같이 마치 배열 처럼 나열하여 표현하면 된다.
    • enum 명은 클래스와 같이 첫 문자를 대문자로하고 나머지는 소문자로 구성한다
    • 관례적으로, 열거 상수는 모두 대문자로 작성한다
    • 열거 상수가 여러 단어로 구성될 경우, 단어 사이를 밑줄 (_)로 연결한다
Java
Java
Java

Enum 메서드 종류

  • String 같은 자바의 여러 클래스가 자체 내장 메소드를 가지고 있듯이, enum 역시 내장 메소드를 지니고 있다.
  • 모든 Enum 타입은 컴파일 시에 java.lang.Enum 클래스를 상속하게 되어있기 때문에, java.lang.Enum 에 선언된 메소드를 이용할 수 있다.
메서드설명리턴 타입
name()열거 객체의 문자열을 리턴String
ordinal()열거 객체의 순번(0부터 시작)을 리턴int
compareTo()열거 객체를 비교해서 순번 차이를 리턴int
valueOf(String name)문자열을 입력받아서 일치하는 열거 객체를 리턴enum
values()모든 열거 객체들을 배열로 리턴enum[]

Enum이 없었을 때 문제

Java
  • 하지만 인터페이스로 상수를 정의하는 방법에도 문제가 있다.

  • 조금 원론적인 문제이긴 한데, 상수가 결국은 정수값이라는 문제이다.

  • 상수는 '변하지 않는 값'이라는 의미이지만 '고유한 값' 이라는 의미도 어느정도 내포하고 있다.

  • 그래서 아래 코드 처럼 다른 집합에 정의된 상수들 끼리 서로 비교하는 로직이 가능하거나, 잘못된 상수가 할당되었음에도 결국은 정수값이기 때문에 컴파일 에러없이 실행된다는 점이다.

  • 이것이 무엇이 문제냐 일수도 있겠지만 프로그램 크기가 커질수록 개발자의 실수가 잦아지며 이러한 제약적이지 않는 요소들 때문에 프로그램에 버그가 발생하게 되는 것이다.

Java

java-enum

자체 클래스 상수

  • 따라서 상수를 정수값으로 구성하는 것이 아니라 독립된 고유의 객체로 선언하자는 취지로 자체 클래스(Class) 인스턴스(Instance)화를 이용해 상수처럼 사용하는 기법이 등장하였다.

  • 자기 자신 객체(Object)를 인스턴스(Instance)화 하고 final static 화 함으로써 고유의 객체를 얻게되어 이를 상수처럼 활용하는 것이다.

Java
  • 하지만 가독성이 다시 안좋아졌고, 무엇보다 이러한 방식은 if문에서는 문제는 없지만 switch문에서 사용할수 없다는 큰 단점이 있다. 
  • 그 이유는 switch 문의 조건에 들어가는 데이터 타입이 제한적이기 때문이다.
Java

java-enum

java-enum

  • 이러한 문제들 때문에 자바에서는 아예 상수만을 다루는 enum 타입 클래스를 만들어 배포한 것이다.
  • 위의 상수 코드를 enum 으로 바꿔보면 다음과 같다.
Java
  • enum의 핵심은 이러한 상수를 단순히 정수로 치부하지말고 객체 지향적으로 객체화해서 관리하자는 취지이다.

  • 예를들어 C언어의 enum은 그냥 정수이며, C++의 enum은 타입이지만, 자바의 enum은 인터페이스와 같이 독립된 특수한 클래스로 구분한다.

  • 즉, 일종의 객체(Object)이기 때문에 힙(heap) 메모리에 저장되며 각 enum 상수들은 별개의 메모리 주소값을 가짐으로써 완벽히 독립된 상수를 구성할 수 있는 것이다.

  • 또한 IDE에서 클래스 파일을 생성할때 독립된 열거형 파일도 생성할 수 있다.(독립된 클래스이기 때문에)

Enum의 장점

  • 코드가 단순해지며 가독성이 좋아진다

  • 허용 가능한 값들을 제한하여 유형 안전(type safe)을 제공한다.

  • 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 나타낼 수 있다.

  • 자체 클래스 상수와 달리 switch문에서도 사용할 수 있다

  • 단순 상수와 비교해 IDE의 적극적인 지원을 받을 수 있다 (자동완성, 오타검증, 텍스트 리팩토링 등등)

  • 리팩토링시 변경 범위가 최소화 된다 (enum에서 한번에 관리하기 때문에 내용의 추가가 필요하더라도, Enum 코드외에 수정할 필요가 없다)

  • enum은 본질적으로 Thread safe인 싱글톤 객체 이므로 싱글톤 클래스를 생성하는데에도 사용된다

  • 추가적으로 enum 성능은 어떨가 싶지만, 정수 상수와 다르지 않으며 열거 타입을 메모리에 올리는 공간과 초기화 시간이 있지만 체감될 정도는 아니다.

Synapse Map Insight

// 요일 열거 타입 enum Week { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
// 계절 열거 타입 enum Season { Spring, Summer, Autumn, Winter }
enum LoginResult { LOGIN_SUCCESS, LOGIN_FAILED }
interface DAY { int MONDAY = 1; int TUESDAY = 2; int WEDNESDAY = 3; int THURSDAY = 4; int FRIDAY = 5; int SATURDAY = 6; int SUNDAY = 7; } interface MONTH { int JANUARY = 1; int FEBRUARY = 2; int MARCH = 3; int APRIL = 4; int MAY = 5; int JUNE = 6; int JULY = 7; int AUGUST = 8; int SEPTEMBER = 9; int OCTOBER = 10; int NOVEMBER = 11; int DECEMBER = 12; }
public static void main(String[] args) { int day = DAY.MONDAY; // 상수를 비교하는 논리적으로 잘못된 행위를 함으로써 day 변수에 다른 상수값이 들어가버림 if (DAY.MONDAY == MONTH.JANUARY) { // ... day = MONTH.JANUARY; } // day 변수에 있는 상수는 MONTH 상수이기 때문에 조건문에서 걸러져야 되지만, // 결국 정수값이기 때문에 에러가 안나고 그대로 수행됨 -> 프로그램 버그 발생 가능성 switch (day) { case DAY.MONDAY: System.out.println("월요일 입니다."); break; case DAY.TUESDAY: System.out.println("화요일 입니다."); break; case DAY.WEDNESDAY: System.out.println("수요일 입니다."); break; } }
class Day { // 자기 자신 객체를 인스턴스화 하고 final static 화 함으로써 고유의 객체 상수를 얻게 됨 public final static Day MONDAY = new Day(); public final static Day TUESDAY = new Day(); public final static Day WEDNESDAY = new Day(); } class Month { public final static Month JANUARY = new Month(); public final static Month FEBRUARY = new Month(); public final static Month MARCH = new Month(); }
public static void main(String[] args) { Day day = Day.MONDAY; // if문은 문제 없지만 if(day == Day.MONDAY) { System.out.println("월요일 입니다."); } // switch문에서는 사용할수 없다 switch (day) { case DAY.MONDAY: System.out.println("월요일 입니다."); break; case DAY.TUESDAY: System.out.println("화요일 입니다."); break; case DAY.WEDNESDAY: System.out.println("수요일 입니다."); break; } }
enum Day{ MONDAY,TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY; } enum Month{ JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER; }