🏃♂️ 들어가기 앞서..
본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕
*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.
enum
)여러 상수를 선언해야 할 때,
" 관련된 상수들을 같이 묶어 놓은 것 " (Java는 타입에 안전한 열거형 제공)
class Card {
static final int CLOVER = 0;
static final int HEART = 1;
static final int DIAMOND = 2;
static final int SPADE = 3;
static final int TWO = 0;
static final int THREE = 1;
static final int FOUR = 2;
final int kind;
final int num;
}
// 열거형으로 선언
class Card {// 0 1 2 3
enum Kind { CLOVER, HEART, DIAMOND, SPADE }
enum Value { TWO, THREE, FOUR }
final Kind kind ; // 타입 int 아님 주의!! Kind 타입
final Value value ;
}
여러가지 상수를 선언할 때
번거로운 선언 작업들을 enum
을 통해 간단하게 선언할 수 있다.
처음 코드처럼 따로 값을 지정해주지 않아도
자동적으로 0부터 시작하는 정수값이 할당 된다.
또한
해당 상수들을 사용하는 경우에서도
활용하고자 하는 의도에 맞게 타입이 분류되어야 하는데
처음 코드를 적용했을 경우에는
Card.CLOVER == Card.TWO
와 같은 논리연산자를 수행하게 되면
true
가 반환되게 된다.
하지만 쓰고자 하는 의도대로라면 false
여야하는데
의미가 어긋나게 되는 것이다.
이런 경우
enum
은 간편한 선언뿐만 아니라
열거형을 이용해 선언한 상수들의 비교는
" 값 비교에 앞서 타입 비교를 선행 "하기 때문에
값이 같을 수도 있는 상수들간에 분류를 할 수 있다.
▶ 아래 열거형으로 선언한 상수들에 대해
Card.CLOVER == Card.TWO
와 같은 논리연산자를 수행하게 되면
타입이 다르기 때문에 컴파일 에러가 발생게 된다.
괄호
{}
안에 상수의 이름을 나열enum (열거형 이름) { 상수명 1, 상수명 2, ... }
- 사용 방법 :
(열거형 이름).(상수명)
사용 방법은 .
을 통해서 각 열거형들에 속해있는 상수들을 사용할 수 있고
상수간의 비교에 compareTo()
와 더불어 ==
도 사용할 수 있다.
==
연산자가 사용 가능하다는 것은 함수를 통해 비교보다
더 빠른 성능의 비교가 가능해지는 것이다.
==
연산자 : true / false 반환compareTo()
사용 _ 왼쪽이 크면 양수 / 오른쪽이 크면 음수하지만 <
나 >
비교연산자는 사용할 수 없다는 점 주의하자.
( 열거형에서 각 상수들은 객체로서 취급되기 때문에 해당 비교연산자들이 적용되지 않는다. )
java.lang.Enum
※ 모든 열거형 →
Enum
자손
Method | 설명 |
---|---|
Class<E> getDeclaringClass() | 열거형의 Class 객체 반환 |
String name() | 열거형 " 상수의 이름 문자열로 " 반환 |
int ordinal() | 열거형 상수가 " 정의된 순서 " 반환 |
T valueOf( Class<T> enumType, String name ) | 지정 열거형에서 " name과 일치하는 열거형 상수 " 반환 |
※ 컴파일러가 자동으로 추가
values()
: 열거형 객체에 정의된 모든 상수 " 배열 " 반환valueOf( String name )
: 열거형 상수의 이름으로 문자열 상수에 대한 참조static E[] values() static E valueOf( String name ) enum Direction {EAST, SOUTH, WEST, NORTH} /* 상수 하나하나가 객체로 다뤄지게 됨 */ Direction[] dArr = Direction.values() ; for (Direction d : dArr) System.out.println("%s=%d%n", d.name(), d.ordinal() ); // 열거형 내 상수들 하나씩 name메서드 & ordinal메서드 Direction d = Direction.valueOf("WEST") ; System.out.println(d) ; // WEST 출력 System.out.println(Direction.WEST == Direction.valueOf("WEST")) ; // 상수에 대한 참조 가져와서 비교 _ true
위에서 알아본 다양한 메서드들의 쓰임 예시를 살펴보자.
우선
열거형의 상수를 얻어오는 방법에 대해 알아보자.
enum Direction {EAST, SOUTH, WEST, NORTH}
...
/* 열거형 상수 가져오기 */
Direction d1 = Direction.EAST
Direction d2 = Direction.valueOf("WEST")
// Enum은 모든 열거형의 조상으로 해당 조상클래스의 valueOf 메서드를 사용하게 되면
// 인수를 String name에 앞서 대상 객체를 지정해줘야 한다.
Direction d3 = Enum.valueOf( Direction.class, "EAST" ) ;
위와 같은 방법으로 열거형의 상수를 가져올 수 있고
다음으로
열거형 상수 간 비교하는 방법을 알아보자.
System.out.println( "d1=" + d1 ); // EAST
System.out.println( "d2=" + d2 ); // WEST
System.out.println( "d3=" + d3 ); // EAST
System.out.println( d1 == d2 ); // false
System.out.println( d1 == d3 ); // true
System.out.println( d1.equals(d3) ); // true
// System.out.println( d1 > d3 ); // 앞서 설명했듯이 각 상수는 객체로 취금 → 에러!! XXXXXX
System.out.println( d1.compareTo(d3) ); // 0
System.out.println( d1.compareTo(d2) ); // -2
/* EAST Side 출력 */
switch( d1 ) {
case EAST : // ★ Direction.EAST 라고 쓰면 불가능
System.out.println("EAST Side"); break;
case SOUTH :
System.out.println("SOUTH Side"); break;
case WEST :
System.out.println("WEST Side"); break;
case NORTH :
System.out.println("North Side"); break;
default :
System.out.println("Invalid Direction.") ; break;
}
앞서 살펴봤었던
Enum
클래스의 정의 메서드 ordinal()
이
" 열거형 상수의 정의 순서 "를 반환한다고 설명했는데
이 순서 값은
자동적으로 0부터 시작하는 정수값이 할당된 것 이며
그저 내부적인 용도로만 쓰기 위한 것이기 때문에
" 열거형 상수의 값 " 으로 사용하는 것은 바람직하지 않고
《 열거형 상수의 값이 불규칙적인 경우 / 다르게 하고 싶은 경우 / 여러 값을 가지게 하고 싶을 경우 》에는
[ 첫번째 ]
상수의 이름 옆에
()
와 함께 원하는 값을 적으면 된다.
enum Direction { EAST(1), SOUTH(5), WEST(-1), NORTH(10) }
[ 두번째 ]
지정된 값을 저장할 수 있는 인스턴스 변수 & 생성자를
새로 추가해주어야 한다.
( 단, 먼저 열거형 상수를 모두 정의한 다음, 다른 멤버 추가작업을 수행해야한다. )
enum Direction {
EAST(1), SOUTH(5), WEST(-1), NORTH(10) ; // ★ ; 세미콜론 잊지 않게 주의
private final int value ; // 정수 저장을 위한 인스턴스 변수 추가
// private 생략 ← Direction 생성자
Direction(int value) { // 생성자 추가
this.value = value ; // 각 상수가 가지는 값들에 대해 정의
}
public int getValue() { //외부에서도 위 값들을 얻을 수 있도록 public 메서드 정의
return value ;
}
}
/* 생성자는 private 이기때문에
외부에서 객체 생성 불가능!!! */
Direction d = new Direction(1) ; // 불가능!!!!!
주의할 점은
" 외부에서 생성자 호출 "이 불가능하다는 것 정도인 것 같다.
<더 알아보기>
enum Direction {
// 상수에 2개 이상의 값이 들어갈 경우
EAST(1, ">"), SOUTH(2, "V"), WEST(3, "<"), NORTH(4, "^" ;)
// 이번엔 배열로 저장되는 내부 인스턴스 변수 추가
private static final Direction[] DIR_ARR = Direction.values();
private final int value ; // 정수 저장을 위한 인스턴스 변수 추가
private final String value ; // 문자열 저장을 위한 인스턴스 변수 추가
// Direction 생성자
Direction(int value, String symbol) { // 생성자 추가
// 각 상수가 가지는 값들에 대해 정의
this.value = value ;
this.symbol = symbol;
}
public int getValue() { return value; }
public String getSymbol() { return symbol; }
// 위에 만들었던 배열 인스턴스 변수를 사용하는
// 외부에서 메서드는 쓸 수 있게끔 public 메서드 선언
public static Direction of( int dir ) {
if (dir < 1 || dir > 4) // 위 상수들의 value 값 범위를 벗어날 경우
// 예외 발생시키지
throw new IllegalArgumentException("Invalid value :" + dir ) ;
return DIR_ARR[dir -1] // 순서에 맞는 값 반환
/* EAST 상수의 value : 1
1 에서 -1 한 값은 0 → 실제 EAST 상수의 index와 동일*/
}
}