김영한 선생님의 자바 중급을 듣고 정리한 내용입니다.
1. 문자열과 타입 안정성 - 문자열
Java가 제공하는 Enum Type을 왜 사용하는지에 대해서 알아보자.
만약 Enum Type을 사용하지 않고 문자열을 사용한다면 다음의 문제들이 발생할 수 있다.
- 타입 안정성 부족 : 문자열의 경우 오타가 발생하기 쉽고 유효하지 않은 값이 입력될 수 있다.
- 데이터 일관성 부족 : 다양한 형식으로 문자열이 입력될 수 있어서 일관성이 떨어질 수 있다.
- 값의 제한 부족
- 컴파일 시 오류 감지 불가
이런 문제를 해결하려면 문자열이 아닌 특정 범위로 값을 제한해야 한다.
예를 들어 BASIC, GOLD, DIAMOND라는 정확한 문자만 사용될 수 있어야 한다.
하지만 String 클래스는 어떤 문자들 받을 수 있기 때문에 Java 입장에서는 아무런 문제가 되지 않는다.
따라서 String을 사용하는 것을 매우 좋지 않은 방식이다.
2. 문자열과 타입 안정성2 - 문자열 상수
문자열 상수를 사용하면 상수의 이름을 잘못 입력할 경우 컴파일 시점에 오류가 발생하기 때문에 에러 캐리도 쉬워진다.
하지만 문자열 상수를 사용해도 String 타입이기 때문에 어떤 문자열이든 입력할 수 있다.
따라서 개발자가 실수로 문자열 상수를 사용하지 않고 직접 문자열을 사용해도 막을 수 있는 방법은 없다.
3. 타입 안전 열거형 패턴
Type-Safe Enum Pattern
3.1. Enum Pattern을 직접 구현해보기
- 회원 등급을 다루는 클래스를 만들고 각 회원 등급별로 상수를 선언
- 각각의 상수마다 별도의 인스턴스를 생성하고 생성한 인스턴스를 대입한다.
- 상수로 선언하기 위해 static final을 사용한다.
- static : 메서드 영역에 선언
- final : 인스턴스(참조값)를 변경할 수 없게 한다.
각각의 상수는 ClassGrade 타입을 기반으로 인스턴스를 만들었기 때문에 getClass() 결과는 모두 동일
각각의 상수는 서로 다른 ClassGrade 인스턴스를 참조하기 때문에 ref (x001, x002, x003) 값을 다르게 출력
- discount() 메서드는 매개변수로 ClassGrade 클래스를 사용한다.
- 값을 비교할 때는 classGrade == ClassGrade.BASIC와 같이 == 참조값(Ref) 비교를 사용한다. → 매개변수로 넘어오는 인수도 ClassGrade가 가진 상수 중에 하나를 사용한다.
3.1.1. Private 생성자
위의 방식은 외부에서 임의로 ClassGrade 인스턴스를 생성할 수 있다는 문제가 있다.
→ 이 문제를 해결하려면 ClassGrade를 외부에서 생성할 수 없도록 해야 한다. 기본 생성자를 private으로 변경해야 한다.
3.2. Enum Pattern을 직접 구현해보기 - private 생성자
public class ClassGrade {
public static final ClassGrade BASIC = new ClassGrade();
public static final ClassGrade GOLD = new ClassGrade();
public static final ClassGrade DIAMOND = new ClassGrade();
//private 생성자 추가
private ClassGrade() {}
}
private 생성자를 사용해서 외부에서 ClassGrade 인스턴스를 임의로 생성할 수 없게 했다.
ClassGrade 클래스 내부에서만 ClassGrade 인스턴스를 생성할 수 있게 되었다.
이로 인해 ClassGrade 타입에 값을 전달할 때 BASIC, GOLD, DIAMOND 상수만 사용할 수 있게 되었다.
Type-Safe Enum Pattern 장점
- 타입 안정성 향상 : 정해진 객체만 사용할 수 있기 떄문에, 잘못된 값을 입력하는 문제를 근본적으로 방지할 수 있다.
- 데이터 일관성 : 정해진 객체만 사용하므로 데이터의 일관성이 보장된다.
- 제한된 인스턴스 생성 : 클래스는 사전에 정의된 몇 개의 인스턴스만 생성하고, 외부에서는 이 인스턴스들만 사용할 수 있도록 한다. 이를 통해 미리 정의된 값을만 사용하도록 보장한다.
- 타입 안정성 : 잘못된 값이 할당되거나 사용되는 것을 컴파일 시점에 방지할 수 있게 된다.
4. 열거형 - Enum Type
자바의 enum은 타입 안정성을 제공하고, 코드의 가독성을 높이며, 예상 가능한 값들의 집합을 표현하는 데 사용된다.
- 열거형을 정의할 때 class 대신 enum을 사용한다.
- 원하는 상수의 이름을 나열하면 된다.
package lang.enum_ex3;
public enum Grade {
BASIC, GOLD, DIAMOND
}
열거형을 정의할 때는 class 키워드 대신 enum 키워드를 활용한다.
원하는 상수의 이름을 나열하기만 하면 된다.
열거형으로 작성한 Grade는 다음 코드와 거의 같다고 이해하면 된다.
public class Grade extends Enum {
public static final Grade BASIC = new Grade();
public static final Grade GOLD = new Grade();
public static final Grade DIAMOND = new Grade();
//private 생성자 추가
private Grade() {}
}
- 열거형도 클래스이다. 다만 자바에서 쉽게 사용할 수 있도록 enum 키워드를 제공하는 것 뿐이다.
- 열거형은 자동으로 java.lang.Enum을 상속받는다.
- 외부에서 임의로 생성할 수 없다.
- 상수들이 열거형으로 선언한 타입인 Grade 타입을 사용하는 것을 확인할 수 있다. 그리고 각 인스턴스도 서로 다르다.
- 열거형은 toString()을 오버라이딩하기 때문에 참조값을 직접 확인할 수 없다. 참조값을 구하기 위해 getRefValue() 메서드를 만들었다.
- System.identityHashCode(grade) : 자바가 관리하는 객체의 참조값을 숫자로 반환한다.
- Integer.toHexString() : 숫자를 16진수로 변환해준다.
4.1. 열거형의 주요 메서드
열거형은 java.lang.Enum 클래스를 자동으로 상속받는다. → 따라서 해당 클래스가 제공하는 메서드들을 사용할 수 있다.
- values() : 모든 ENUM 상수를 포함하는 배열을 반환한다.
- valueOf(String name) : 주어진 이름과 일치하는 ENUM 상수를 반환한다.
- name() : ENUM 상수의 이름을 문자열로 반환한다.
- ordinal() : ENUM 상수의 선언 순서를 반환한다.
- toString() : ENUM 상수의 이름을 문자열로 반환한다. (직접 오버라이딩 가능)
> 가급적 ordinal()은 사용하지 않는 것이 좋음
→ 중간에 상수를 선언하는 위치가 변경되면 전체 상수의 위치가 변경될 수 있으며 큰 버그가 발생할 가능성이 있다.
4.1.1. 열거형 정리
- 열거형은 java.lang.Enum을 자동으로 상속받는다. → Enum 클래스의 여러 메서드를 활용할 수 있다.
- 다른 클래스를 추가로 상속받을 수 없다.
- 열거형은 인터페이스를 구현할 수 있다.
- 열거형에 추상 메서드를 선언하고, 구현할 수 있다. → 이 경우 익명 클래스와 같은 방식을 사용한다.
'Programming > Java' 카테고리의 다른 글
[Java] 김영한의 자바 중급 1편 #7 - 중첩 클래스, 내부 클래스 - 1 (0) | 2024.10.04 |
---|---|
[Java] 김영한의 자바 중급 1편 #6 - 날짜와 시간 라이브러리 (0) | 2024.09.30 |
[Java] 김영한의 자바 중급 1편 #4 - 래퍼 클래스 (0) | 2024.09.30 |
[Java] 김영한의 자바 중급 1편 #3 - String 클래스 (0) | 2024.09.10 |
[Java] 김영한의 자바 중급 1편 #2 - 불변 객체 (0) | 2024.09.06 |