반응형

2.1 열거형 이란?

 - 실제 값이 같아도 타입이 다르면 조건식의 결과가 false가 된다.

 

예)

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 {

enum Kind { CLOVER, HEART, DIAMOND, SPADE }

enum Value { TWO, THREE, FOUT }

 

final Kind kind;

final Value value;

}

 

if (Card.CLOVER == Card.TWO) // true 지만 false이어야 의미상 맞음

if (Card.kind.CLOVER == Card.Value.TWO) // false. 값은 같지만 타입이 다름

 

2.2 열거형의 정의와 사용

 - enum 열거형 이름 { 상수명1, 상수명2, ...}

 

enum Direction {EAST , SOUTH, WEST, NORTH}

 

class Unit{

int x,y; // 유닛의 위치

Direction dir; // 열거형을 인스턴스 변수로 선언

 

void init(){

dir = Direction.EAST; // 유닛의 방향을 EAST로 초기화

}

}

 

- 상수간 비교에는 '=='를 사용할 수 있다.

'<','>' 처럼비교연산자는 사용할 수 없고 compareTo()는 사용가능 하다. compareTo()는 두 비교대상이 같으면 0, 왼쪽이 크면 양수, 오른쪽이 크면 음수를 반환한다.

 

if (dir ==Direction.EAST){

x++;

}

else if (dir>Direction.WEST){ // 비교연산자 사용불가.

}

 

else if (dir.compareTo(Direction.WEST) >0){

}

 

- switch문의 조건식에도 열거형을 사용할 수 있다.

void move(){

switch(dir){

case EAST: x++; // Direction.EAST라고 쓰면안됨.

break;

case WEST: x--;

break;

case SOUTH: y++;

break;

case NORTH: y--;

break;

}

}

 

 // case문에 열거형의 이름은 적지 않고 상수의 이름만 적어야 한다는 제약이 있다.

 

- 열거형의 조상 java.lang.Enum

열거형 Direction에 정의된 모든 상수를 출력하려면?

 

Direction[] dArr = Direction.Values();

 

for (Direction d : dArr)

System.out.printf("%s = %d%n", d.name(), d.ordinal());

 

- Values() 는 열거형의 모든 상수를 배열에 담아 반환한다. 이 메서드는 모든 열거형이 가지고 있는것으로 컴파일러가 자동으로 추가해 준다.

- ordinal()은 모든 열거형의 조상인 java.lang.Enum클래스에 정의된 것으로 열거형 상수가 정의된 순서를 정수로 반환한다.

 

이외 Enum클래스 메서드 정의

- Calss <E> getDeclaringCalss() : 열거형의 calss객체를 반환한다.

- String name() : 열거형의 상수의 이름을 문자열로 반환한다.

- int ordinal() : 열거형 상수가 정의된 순서를 반환한다.(0부터시작)

- T valueOf(Calss<T> enumType, Sting name) : 지정된 열거형에서 name과 일치하는 열거형 상수를 반환한다.

 

 

 

 

예제.

 

 

package enumeration;

enum Direction { EAST, SOUTH, WEST, NORTH}

 

public class enums{

        public static void main(String[] args) {

               Direction d1 = Direction.EAST;

               Direction d2 = Direction.valueOf("WEST");

               Direction d3 = Enum.valueOf(Direction.class, "EAST");

              

               System.out.println("d1="+d1);

               System.out.println("d2="+d2);

               System.out.println("d3="+d3);

              

               System.out.println("d1 ==d2 ?" +(d1==d2));

               System.out.println("d1 ==d3 ?" +(d1==d3));

               System.out.println("d1.equals(d3) ?" +d1.equals(d3));

               //System.out.println("d2>d3?" +(d1>d3)); // 에러

               System.out.println("d1.compareTo(d3)?" +(d1.compareTo(d3)));

               System.out.println("d1.compareTo(d2)?" +(d1.compareTo(d2)));

              

               switch(d1) {

               case EAST:

                       System.out.println("The direction is EAST.");

                       break;

               case SOUTH:

                       System.out.println("The direction is SOUTH");

                       break;

               case WEST:

                       System.out.println("The direction is WEST");

                       break;

               case NORTH:

                       System.out.println("The direction is NORTH");

                       break;

               default:

                       System.out.println("Invalid direction.");

                       break;

               }

              

               Direction[] dArr = Direction.values();

              

               for(Direction d: dArr)

                       System.out.printf("%s=%d%n", d.name(),d.ordinal());

        }

}

 

 

출력 결과 :

d1=EAST
d2=WEST
d3=EAST
d1 ==d2 ?false
d1 ==d3 ?true
d1.equals(d3) ?true
d1.compareTo(d3)?0
d1.compareTo(d2)?-2
The direction is EAST.
EAST=0
SOUTH=1
WEST=2
NORTH=3

 

2.3 열거형에 멤버 추가하기.

 

열거형 상수의 값이 불규칙적인 경우 이때는 다음과 같이 열거형 상수의 이름 옆에 원하는 값을 괄호()와 함께 적어주면 된다.

 

enum Direction { EAST(1), SOUTH(5), West(-1), NORTH(10)}

 

그리고 지정된 값을 저장할 수 있는 인스턴스 변수와 생성자를 새로 추가해 주어야 한다.

 주의할 점은 열거형 상수를 정의한 다음에 다른 멤버들을 추가해야 한다.

 

enum Direction {

EAST(1), SOUTH(5), West(-1), NORTH(10);

 

private final int value; // 정수를 저장할 필드(인스턴스 변수)

Direction(int value){this.value = value;}

 

public int getValue(){ return value;}

}

 

// Direction d = new Direction(1); 에러. 열거형의 생성자는 외부에서 호출 불가.

 

열거형의 생성자는 제어가자 묵시적으로 private이다.

 

필요에 따라 열거형 상수에 여러 값을 지정할 수도 있다. 다만 그에 맞게 인스턴스 변수와 생성자 등을 새로 추가해 주어야 한다.

 

enum Direction {

EAST (1,">"), SOUTH(2,"V"), WEST(3,"<"), NORTH(4,"^");

 

private final int value;

private final String symbol;

 

Direction(int value, Sting symbol){

this.value = value;

this.symbol = symbol;

}

 

public int getValue(){ return value;}

public String getSymbol() { return symbol;}

}

 

예제 2.

package enumeration;

enum Direction {

        EAST (1,">"), SOUTH(2,"V"), WEST(3,"<"), NORTH(4,"^");

       

        private static final Direction[] DIR_ARR = Direction.values();

        private final int value;

        private final String symbol;

       

        Direction(int value, String symbol){

               this.value = value;

               this.symbol = symbol;

        }

 

 

        public int getValue() {return value;}

        public String getSymbol() {return symbol;}

       

        public static Direction of(int dir) {

               if (dir <1||dir >4) {

                       throw new IllegalArgumentException("Invalid value :"+dir);

               }

               return DIR_ARR[dir-1];

        }

        public Direction rotate(int num) {

               num = num%4;

               if(num <0)num+=4;

               return DIR_ARR[(value-1+num)%4];

        }

        public String otString() {

               return name()+getSymbol();

        }

}

public class enums1 {

 

        public static void main(String[] args) {

               for(Direction d: Direction.values())

                       System.out.printf("%s=%d%n", d.name(),d.getValue());

       

        Direction d1 = Direction.EAST;

        Direction d2 = Direction.of(1);

       

        System.out.printf("d1=%s, %d%n", d1.name(),d1.getValue());

        System.out.printf("d2=%s, %d%n", d2.name(),d2.getValue());

       

        System.out.println(Direction.EAST.rotate(1));

        System.out.println(Direction.EAST.rotate(2));

        System.out.println(Direction.EAST.rotate(-1));

        System.out.println(Direction.EAST.rotate(-2));

        }

 

}

 

 

출력 결과:

 EAST=1

SOUTH=2

WEST=3

NORTH=4

d1=EAST, 1

d2=EAST, 1

SOUTH

WEST

NORTH

WEST


* 열거형에 추상 메서드 추가하기

열거형 Transportation은 운송 수단의 종류 별로 상수를 정의하고 있으며, 각 운송 수단에는 기본요금(BASIC_FARE)이 책정되어 있다.

enum Transportation {
BUS(100), TRAIN(150), SHIP(100), AIRPLANE(300);

private static final BASIC_FARE;

private Transportation(int basicFare) {
BASIC_FARE = basicFare;
}

int fare(){ //운송요금 반환
return BASIC_FARE;
}
}

거리에 따라 요금을 계산하는 방식이 각 운송 수단마다 다를 것이다.
이럴 때, 열거형에 추상 메서드 'fare(int distance)' 를 선언하면 각 열거형 상수가 이 추상 메서드를 반드시 구현해야 한다.

enum Transportation {
BUS(100) {
int fare(int distance) { return distance*BASIC_FARE; }
},
TRAIN (150) {
int fare(int distance) { return distance*BASIC_FARE; }
},
SHIP(100) {
int fare(int distance) { return distance*BASIC_FARE; }
},
AIRPLANE(300){ 
int fare(int distance) { return distance*BASIC_FARE; }
};

abstract int fare(int distance); //거리에 따른 요금 계산하는 추상 메서드

protected final int BASIC_FARE; // protected로 해야 각 상수에서 접근 가능

Transportation(int basicFare) {
BASIC_FARE = basicFare;
}

public int getBasicFare() {return BASIC_FARE;}
}

예제 3. 
 

package enumeration;

 

enum Transportation {

        BUS(100) { int fare(int distance) {return distance*BASIC_FARE;}},

        TRAIN(150)     { int fare(int distance) {return distance*BASIC_FARE;}},

        SHIP(100){int fare(int distance) {return distance*BASIC_FARE;}}, 

        AIRPLANE(300){int fare(int distance) {return distance*BASIC_FARE;}};

  

        protected final int BASIC_FARE;

 

        Transportation(int basicFare){

               BASIC_FARE = basicFare;

        }

 

        public int getBasicFare() {  return BASIC_FARE;}

 

        abstract int fare(int distance);

}

public class enums1 {

        public static void main(String[] args) {

               System.out.println("bus fare ="+Transportation.BUS.fare(100));

               System.out.println("train fare ="+Transportation.TRAIN.fare(100)); 

               System.out.println("ship fare ="+Transportation.SHIP.fare(100)); 

               System.out.println("airplane fare ="+Transportation.AIRPLANE.fare(100));

        }

}

 

 

 


출력 결과.
bus fare =10000
train fare =15000
ship fare =10000
airplane fare =30000

2.4 열거형의 이해

enum Direction { EAST, SOUTH, WEST, NORTH }

거형 상수 하나하나가 Direction 객체이다. 위의 문장을 클래스로 정의 하면 다음과 같다.

class Direction{
static final Direction EAST = new Direction("EAST");
static final Direction SOUTH = new Direction("SOUTH");
static final Direction WEST = new Direction("WEST");
static final Direction NORTH = new Direction("NORTH");

private String name;

private Direction(String name){
this.name = name;
}

}



모든 열거형은 추상 클래스 Enum의 자손이므로, Enum을 흉내 내서 MyEnum을 작성하면 다음과 같다.


abstract class MyEnum<T extends MyEnum<T>> implements Comparable<T> {

static int id =0; // 객체에 붙일 일련번호


int ordinal;

String name ="";


public int ordinal(){ return ordinal;}


MyEnum(String name){

this.name =name;

ordinal =id++;

}


public int compareTo(T t){

return ordinal - t.ordinal();

}

}

/*

객체가 생성될 때마다 번호를 붙여서 인스턴스 변수 ordinal 에 저장, 그리고 comparable 인터페이스를 구현해서 열거형 상수간의 비교가 가능하도록 되어있다.


두 열거형 상수의 ordinal값을 서로 빼주기만 하면 된다. 만일 클래스를 MyEnum<T>와 같이 선언하였다면, compareTo()를 위와 같이 간단히 작성할 수 없었을 것이다. 타입 T에 ordinal()이 정의되어 있는지 확인할 수 없기 때문이다.

*/ 이해가 잘안가는 부분...


abstract class MyEnum<T> implements Comparable<T> {

public int compareTo(T t) {

return ordinal - t.ordinal(); // 에러 타입 T에 ordinal()이 있나?

}

}



그래서 MyEnum<T extends MyEnum<T>>와 같이 선언 한 것이며, 이것은 타입 T가 MyEnum<T>의 자손이어야 한다는 의미이다. 타입 T가 MyEnum의 자손이므로 ordinal()이 정의되어 있는 것은 분명하므로 형변환 없이도 에러가 나지 않는다.


추상 메서드를 새로 추가하면, 클래스 앞에도 abstract를 붙여줘야 하고, 각 static 상수들도 추상 메서드를 구현해 주어야 한다. 아래의 코드에서 익명의 클래스의 형대로 추상메서드를 구현한 예이다.


abstract class Direction extends MyEnum {

static final Direction EAST = new Direction("EAST"){

point move(Point p) {}

};

static final Direction SOUTH = new Direction("SOUTH"){

point move(Point p) {}

};

static final Direction WEST= new Direction("WEST"){

point move(Point p) {}

};

static final Direction NORTH = new Direction("NORTH"){

point move(Point p) {}

};


private String name;


private Direction(String name){

this.name = name;

}


abstract Point move(Point p);

}


예제 4


package enumeration;

 

abstract class MyEnum<T extends MyEnum<T>> implements Comparable<T> {

static int id =0;

 

int ordinal;

String name ="";

 

public int ordinal() { return ordinal;}

 

MyEnum(String name){

this.name = name;

ordinal = id++;

}

  

public int compareTo(T t) {

return ordinal -t.ordinal();

}

}

abstract class MyTransportation extends MyEnum {

static final MyTransportation BUS = new MyTransportation("BUS",100) {

int fare(int distance) {return distance*BASIC_FARE;}

};

 

static final MyTransportation TRAIN = new MyTransportation("TRAIN",100) {

int fare(int distance) {return distance*BASIC_FARE;} 

};

 

static final MyTransportation SHIP = new MyTransportation("SHIP",100) {

int fare(int distance) {return distance*BASIC_FARE;}

};

 

static final MyTransportation AIRPLANE = new MyTransportation("AIRPLANE",100) {

int fare(int distance) {return distance*BASIC_FARE;}

};

 

abstract int fare(int distance);

 

protected final int BASIC_FARE;

 

private MyTransportation(String name, int basicFare) {

super(name);

       BASIC_FARE = basicFare;

}

 

public String name() {return name;}

 

public String toString() {return name;} 

} 

 

 

public class enums2 {

public static void main(String[] args) {

MyTransportation t1 = MyTransportation.BUS; 

MyTransportation t2 = MyTransportation.BUS; 

MyTransportation t3 = MyTransportation.TRAIN; 

MyTransportation t4 = MyTransportation.SHIP; 

MyTransportation t5 = MyTransportation.AIRPLANE;

 

System.out.printf("t1 =%s,%d%n", t1.name(),t1.ordinal());

System.out.printf("t2 =%s,%d%n", t2.name(),t2.ordinal()); 

System.out.printf("t3 =%s,%d%n", t3.name(),t3.ordinal()); 

System.out.printf("t4 =%s,%d%n", t4.name(),t4.ordinal()); 

System.out.printf("t5 =%s,%d%n", t5.name(),t5.ordinal()); 

System.out.println("t1==t2?"+(t1==t2)); 

System.out.println("t1.compareTo(t3)="+t1.compareTo(t3));

} 

}

 

 

 

 



출력 결과

t1 =BUS,0
t2 =BUS,0
t3 =TRAIN,1
t4 =SHIP,2
t5 =AIRPLANE,3
t1==t2?true
t1.compareTo(t3)=-1



반응형

+ Recent posts