본문 바로가기

카테고리 없음

[ Java ] enum타입

Java SE 17 & JDK 17 공식문서에 enum이 Class Enum<... 이렇게 작성되어 있는데 → Enum도 클래스라는 사실

클래스인데 public abstract class Enum<E extends Enum... → Enum은 추상클래스다.

 

enum은 사용할 수 있는 값의 한정, 어떤 변수에 대입될 수 있는 값의 범위를 정할 수 있을 때, 어떤 변수에 대입될 수 있는 값이 정해져 있어서 다른 값이 들어오면 안될 때 → 경우의 수가 많을 때 아예 범위를 정해서 이 범위 안의 값만 대입될 수 있다고 알려주고 싶을 때 enum 클래스를 사용하는 것 같다.

 

enum도 일종의 클래스, 열거형 타입 클래스라고 한다.

어떤 클래스로부터 생성된 객체의 속성중 어떤 변수에 대입될 수 있는 값을 한정하고 싶을 때 enum타입 클래스를 이용한다.

예를 들어 개발자라는 클래스를 작성하는데 이름, 연차, 주력언어(사용하는 언어) 멤버변수를 작성한다면,

이 개발자라는 클래스로부터 생성된 인스턴스는 이름, 연차, 주력언어의 정보를 갖을 수 있고,

개발자가 인스턴스가 갖는 주력언어의 값은 한정할 수 있어 enum 클래스를 만들어 개발자인스턴스.주력언어에는 enum 클래스에 작성된 값만 대입될 수 있도록 설계하는 것이 정해진 타입의 유효한 값만 들어올 수 있게 함으로 타입과 값의 안정성 측면에서 유용한 것 같다. 

 

- enum타입 클래스를 사용한 Developer 클래스 예시

// 개발자 설계도 → 이 클래스를 통해 개발자 인스턴스를 만들 수 있음
public class Developer {
	// 개발자 이름
    public String name;
    
    // 연차
    public int career;
    
    // 사용하는 언어는 무엇인지: 주력언어
    
    /* 주력언어의 타입을 String으로 설계했을 때 문제점 
    	문자열 형식만 대입한다면 그 값이 어떤 값이든 대입될 수 있다.
        
        예를 들면 빈 문자열이나 숫자문자열, 이상한값문자열 등등
        이런 값들이 대입됐을 때 유효하지 않은 값이라 문제가 된다.
        그렇다고 해당 값이 들어왔을 때 유효성 검사를 하기에도 경우의 수가 너무 많다는
        그래서 enum타입 클래스를 사용하여 대입될 수 있는 값의 범위를 한정하는 것
        enum타입 클래스를 사용한다면 타입과 값의 안정성(유효한 값) 측면에서 편리하다.  
    	public String lang;
    */
    
    // lang이라는 속성에 대입될 수 있는 값은 Language라는 enum클래스에 작성된 상수의 값만 허용한다.
    public Language lang;
}

 

- Enum타입 클래스

public enum Language {
	// lang에 대입될 수 있는 값은 어떤 관점으로 바라보느냐에 따라 달라진다.
    
    // 예를 들어 사람을 기준으로 언어를 생각한다면 구사할 수 있는 언어, 모국어 등을 생각하여
    // lang이라는 변수에 대입될 수 있는 값은 "english", "korea" 등을 생각할 수 있다.
    
    // 그런데 개발자가 사용할 수 있는 언어,
    // 사용하는 언어라고 한다면 "javascript", "Java" 등으로 한정된다.

	// enum Language는 개발자 객체가 갖는 lang이라는 변수에 대입될 값을 정해놓은 클래스로
    // Java, javascript, Python 등을 작성한다.
    // enum 클래스는 관련된 상수의 집합으모 대문자로 작성한다.
    
    // 상수("연관시킬 문자값")
    JAVA("자바"),
    JAVASCRIPT("자바스크립트)",
    CPP("C++"),
    C("C"),
    PYTHON("파이썬");
    
    // 상수와 연관시킬 문자 값을 담을 필드를 선언
    private String name;
    
    
    // 외부에서 enum타입의 상수를 사용하면 enum 객체가 생성되고,
    // 위의 상수에 선언한 방식의 생성자 호출문을 통해 연관 문자가 매개값으로 전달되면서
    // name 필드를 초기화 한다.
    // 상수를 통해서만 생성자를 호출할 수 있도록 private으로
    private Languge(String name) {
    	this.name = name;
    }
    
    // 한글이름을 얻어내기 위한 메서드
    public String getName() {
    	return name;
    }
}

 

- main에서 개발자 인스턴스를 생성해서 lang변수에 값 대입해보기

public class Main {
	public static void main(String[] args) {
    	// 개발자 인슨턴스 생성하기
        Developer kim = new Developer();
        kim.name="박모미";
        kim.carrer=3;
        
        // kim.lang에 enum Language에 작성한 값이 아니라면 작성중에 에러가 뜬다.
  		// 값을 대입할 때는 Language타입의,
        // enum Language (클래스)에 존재하는 값을 대입해주어야 하는데
        // enum클래스명.대입할수있는값 을 대입해주면 된다.
        
        // enum 클래스를 사용하면 타입과 값의 안정성 그리고 자동완성 기능으로 개발에 편리하다.
        kim.lang=Language.JAVA; 
        
        System.out.println(kim.lang); // 콘솔 출력 결과: JAVA
        System.out.println(kim.lang.getName()); // 콘솔 출력 결과: 자바 
    }
}

 

Developer클래스로부터 생성된 인스턴스의 lang이라는 변수에는 enum Language에 작성된 상수의 값만 대입할 수 있도록

설계하여 String타입으로 lang이라는 변수를 작성했을 때보다 lang에 대입될 타입이나 값이 안정적이게 되는 장점이 있다.

 

enum을 사용하지 않았을 때의 문제점

- 상수의 값 자체는 변경이 불가하지만, 상수를 받는 객체의 필드 값은 안정적이지 못하다.

static final로 값을 정의하면 그 값 자체는 변경이 불가하지만,

개발자의 lang이라는 필드에 상수가 아닌 다른 값을 넣어도 무방하기 때문이다.

- 상수는 어느 클래스에서나 선언할 수 있기 때문에 무분별한 상수 선언이 이뤄질 수 있음.

- 코드의 가독성 또한 좋지 못하다.

 

enum class를 사용하면 얻을 수 있는 장점

- 코드가 단순해지고 가독성이 좋아진다.

- 정의한 상수 이외의 값을 컴파일 과정에서 막기 때문에 타입의 안정성이 증가한다.

- 관련있는 상수들끼리 모아놓기 때문에 구현의 의도를 명확하게 파악이 가능하다.

 

***enum 활용+

 

현재 enum Language {...} 에는 JAVA, PYTHON, CPP, JAVASCRIPT, C이렇게 작성되어 있는데,

외부에서 enum Language에 작성되어 있는 값을 개발자 인스턴스의 lang변수에 대입하고,

출력했을 때 System.out.println(개발자인스턴스명.lang); 대입한 값이 출력되는데,

JAVA가 아닌 한글명 자바가 출력되게 하고 싶다면, enumLanguage에

 

// 상수("연관시킬 문자")

JAVA("자바"),

PYTHON("파이썬"),

...;

 

이렇게 우선 작성한다.

이 의미는 외부에서 Language라는 enum타입의 상수를 사용할 때, enum타입 Language의 객체를 생성하겠다라는 의미고,

LANGUAGE.JAVA를 사용하게 되면 enum타입 Language의 객체를 생성하게 되고,

JAVA생성자의 매개 값으로 지정된 문자열 "자바"가 전달되면서 객체가 생성된다.

 

그리고 생성자 호출시 어떻게 객체가 생성되어야 하는지를? 선언하고 정의해야 한다.

 

// 우선 상수와 관련된 문자열을 담을 필드를 선언한다.

private final String name;

 

// 그리고 예를 들어, 외부에서 Language.JAVA 사용시

// 아래 생성자가 호출되면서 객체가 생성되고, 생성된 객체의 name변수에는

// 상수 JAVA와 관련된 문자열인 "자바"가 설정되는 것이다.

private Language(String name) {

    this.name = name;

}

 

***

enum 클래스타입의 값을 부르면 enum 클래스에 작성된 값과 관련된 생성자를 호출하고,

enum 객체가 생성되고, 상수옆에 붙어있는 문자열이 enum객체의 name 변수에 대입되는 것이다.

 

name을 선언할 때 private으로 선언했기 때문에 외부에서 직접 접근할 수 없어 getter 메서드를 선언해주어야 한다.

```

 

public String getName() { // 한글 이름을 얻어내기 위한 메서드

    return name;

}

 

```

 

*** 상수를 통해서만 생성자를 호출할 수 있도록 private으로 설정하는 것은 enum타입만 가능한 문법이다.

생성자를 호출하여 enum객체가 생성되는데, 이렇게 생성된 enum객체는 여러 개의 필드를 갖을 수 있으므로

단순히 상수만 지목했을뿐이지만 여러 개의 정보를 얻을 수 있다는 장점이 있다 → 굉장한 장점이라고 개인적으로 생각한다.실무에서 어떻게 유용하게 사용될지 감이 잡히질 않지만 학습차원에서는 신기하게 느껴짐...

 

- enum을 사용하면 기본적으로 사용할 수 있는 메서드

- values(): 열거형 타입에 존재하는 모든 상수를 배열에 담아서 반환하는 메서드예를 들어 열거형 타입인 Laguage에 있는 모든 상수(값)를 얻고 싶다면 Language.values() 를 사용할 수 있고,이 메서드의 반환 타입은 배열이므로  Language[] values = Language.values(); 변수에 담아 해당 변수를 반복문으로 돌려주면출력문을 통해 Language에 작성한 모든 상수를 확인할 수 있다.

 

Language[] values = Language.values();

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

 

출력 결과:

 

- public final int ordinal(): 열거형 타입에 열거되어 있는 순서를 정수값으로 반환하는 메서드, 0번부터 시작- valueOf("str"): 매개 값으로 전달된 문자열과 일치하는 요소를 반환한다. 예를 들어 Language.valueOf("JAVA"); 를 작성하면enum타입 객체인 JAVA 요소가 반환된다.