반응형

자바에서 열거형이 무엇인지 알려드릴게요.


먼저 열거란 무엇인지 사전을 볼까요???



열거 : 여러 가지 예나 사실을 낱낱이 죽 늘어놓음.



죽~ 늘어놓음.


열거형마찬가지예요.




관련된 상수들을 죽 늘어놓은 거예요.


여기서 중요한 것은 모두 상수!!라는 점~





어쩔 때 쓰이냐면


달력을 만든다고 할 때


월요일 화요일 수요일 목요일 ...


이렇게 쓰는 것보다




월요일 = 1

화요일 = 2

수요일 = 3

...



 

이런 식으로 코드화해 놓는 게 효과적일 거예요.




이런 상수들을 모아놓아서 활용하기 쉽게 해주는 것이 열거형이에요.


열거형이라고 하니 자료형과 비슷한 것 같죠?


맞아요!!


자료형처럼 열거형 안에 있는 상수들은 열거형으로 선언돼요!


int a;와 같이


열거형명 데이터;표현돼요.


먼저 열거형을 살펴보기 전에


열거형이 없을 때 어떻게 상수들을 선언했을지 살펴볼게요.



우선 변수로 상수를 선언!!



private final static int MONDAY = 1;

private final static int TUESDAY = 2;

private final static int WEDNESDAY = 3;

private final static int THURSDAY = 4;

private final static int FRIDAY = 5;

private final static int SATURDAY = 6;

private final static int SUNDAY = 7;


이런 식으로 사용하기도 해요.


이때의 문제점은 한번 선언된 변수명을 중복 사용할 수 없다는 것과


상수를 추가해야 할 경우 내용이 많아지며 메모리 공간을 많이 차지한다는 점이에요.



그래서


public final static이 생략되어있는


인터페이스를 이용하거나 class를 이용해요.



interface Day{

    int MONDAY = 1;

    int TUESDAY = 2;

    int WEDNESDAY = 3;

    int THURSDAY = 4;

    int FRIDAY = 5;

    int SATURDAY = 6;

    int SUNDAY = 7;

}


여기서 interface를 이용할 경우에 문제가 있어요.


A1과 A2라는 인터페이스를 만들었을 때


두 인터페이스는 서로 다른 타입이기 때문에 비교가 불가능해야 해요.


그런데 if(A1 == A2) 를 했을 경우 경고 메시지를 볼 수 없다는 것이 문제에요.



그래서


Class를 정의해 사용합니다.



class Day{

   public final static Day MONDAY = new Day();

   public final static Day TUESDAY = new Day();

   public final static Day WEDNESDAY = new Day();

   public final static Day THURSDAY = new Day();

   public final static Day FRIDAY = new Day();

   public final static Day SATURDAY = new Day();

   public final static Day SUNDAY = new Day();

}


마찬가지로 class를 이용할 때도 문제가 있는데


switch 문에서 사용이 불가능하다는 것이에요.


switch(조건)


여기서 조건에 들어가는 데이터 타입이 제한적이라


class를 정의해서 사용할 경우 에러가 발생해요.




이런 문제점을 해결해 주는 것이 enum이에요.



enum Day{

           MONDAY,TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;

}


public class EnumStudy {


           public static void main(String[] args) {

                     // TODO Auto-generated method stub

                     System.out.println("월요일 : " + Day.MONDAY);

                     System.out.println("화요일 : " + Day.TUESDAY);

                     System.out.println("수요일 : " + Day.WEDNESDAY);

                     System.out.println("목요일 : " + Day.THURSDAY);

                     System.out.println("금요일 : " + Day.FRIDAY);

                     System.out.println("토요일 : " + Day.SATURDAY);

                     System.out.println("일요일 : " + Day.SUNDAY);

           }

}




또한 숫자를 사용하고 싶다면 아래처럼 해주면 됩니다.




enum Code{

           ONE(1), TWO(2), THREE(3);

          

           Code(int num){//생성자

                     CodeNum = num;

           }


           int CodeNum;

           public int getCodeNum(){

                     return CodeNum;

           }

}


public class EnumStudy {


           public static void main(String[] args) {

                     // TODO Auto-generated method stub

                     System.out.println(Code.ONE + " : " + Code.valueOf("ONE").getCodeNum());

                     System.out.println(Code.TWO + " : " + Code.valueOf("TWO").getCodeNum());

                     System.out.println(Code.THREE + " : " + Code.valueOf("THREE").getCodeNum());

           }

}





enum을 이용할 때 생성자는 자동으로 private선언돼요.


그래서 타입의 안정성이 보장돼요.


외부에서 접근이 불가능하며 new 키워드로 생성할 수도 없어요.


물론 clone(복사)도 하지 못한답니다~ 

[출처] 자바 :: 열거형 (enum)|작성자 프로

 

 

1.열거형이란?

열거형은 C와 C++에서도 썼던타입으로 특정의 정수와 그 정수를 의미하는 단어로 되어 자료형이였죠.

저의 C언어 12강에서 1번째로 소개했던게 열거형인데요 C와 C++의형태는 뭐 다음과 같습니다.


 

enum은 각각 순서대로 0부터 시작해서 배정되며 원한다면 자기가 다른 숫자를 배정할 수 있습니다.

그리고 enum형에서 정의된 토큰들은 전부 상수이며 값의 수정은 불가능합니다.


원래는 자바에서도 없던 기능이였으나 JDK1.5부터 열거형이 사용이 가능합니다.

사용방식은 C와 유사하게 사용할 수 있으나 자바의 열거형은 이미 하나로 훌륭한 객체입니다.

따라서 C와는 차원이 다르게 높은 레벨로 프로그래밍을 할 수 있습니다.


사용방식은 기존의 Class를 사용하는것 처럼 쓸수도 있고 따로 Enum전용으로 만들 수 있습니다.

뭐 차이라면 public class를 쓰냐 package class를 쓰냐의 차이 처럼 public enum을 쓰고싶으면

전용으로 만들어서 쓰고 package enum을 써도 상관없다면 그냥 아무 class,intefrface,enum등에 같이써도 됩니다.


2.열거형의 사용

java에서 열거형은 기본적인 스탠다드한 형식은 다음과 같습니다.

 

public enum이므로 소스파일을 따로 만들어줘야합니다.

위의 구문의 의미는 Trump라는 열거형은 그 값으로 SPADE,HEART,CLUB,DIAMOND밖에 가지지 못함을 의미합니다.

즉 제일 윗줄에 쓰는 토큰의 나열은 그 열거형이 가질수 있는 값의 전부라고 보시면됩니다.


이번에는 main메소드를 보도록하죠.

 

같은 패키지내에있는 TestMain클래스의 main함수에서 Trump형으로 t를 선언하고 그 값으로 Trump.CLUB을 넣은 모습입니다.

Trump enum은 이미 그 하나로도 interface나 class, abstract class의 객체이지만 생성자를 호출하진 않습니다.

정확히 말하면 생성자를 호출하지 않는건 아니지만 저희가 호출할 일은 없습니다.

enum은 이미 제가 정의해 놓은 값만 소유하는게 가능하며 다른 값을 소유하는건 불가능합니다.

따라서 Tump t형은 CLUB과 SPADE,HEART,DIAMOND만 가지는게 가능합니다.


enum 상수의 호출은 enum_name.enum_const 와 같은 형태로만 접근할 수 있습니다.

위 처럼 Trump.CLUB;같은 형태만 쓸 수 있다는 것이죠.


그리고 위의 예를 봐서 알겠지만 enum형을 그 이름으로 출력할경우에는 문자열로 출력이 됩니다.

따라서 System.out.println(Trump.CLUB);의 구문은 Trump.CLUB은 문자열로 취급되서 출력하게 되는 것이죠.


이미 이 정도만해도 enum의 존재가치는 충분하지만 enum은 여기서 더더욱 나아가서

훨씬 클래스에 근접하게 사용할 수 있습니다. 이는 C와 C++은 누리지 못했던 특권이죠.


 

이 코드는 일반적인 클래스구조와 굉장히 유사합니다. 이 코드하나로 enum의 성질을 대부분알 수 있습니다.

각각의 상수 토큰에는 그 의미를 부여할 수 있습니다.

위의 예시는 SPADE에는 3을 HEART에는 7을 같은 방식으로 나머지에도 값을 부여했습니다.


이렇게 사용하려면

Token(value)

와 같은 형태로 사용해야 합니다.


만약 이런식으로 사용한다면 이제는 명시적으로 생성자를 지정해저야합니다.

위의 SPADE(3)이라는 구문은 생성자의 매개변수가 1개짜리은 생성자를 호출해야만 하겠다 라는 뜻입니다.

따라서 이제는 생성자를 명시적으로 선언해줄 필요가 생깁니다.

단 이 생성자는 저희가 직접쓰는건 아니라 자바가 알아서 적절한 타이밍에서 사용하게 됩니다.

애당초 사용하고싶어도 사용하는것도 불가능 합니다. 이게 불가능한 이유는


보시면 아시겠지만 생성자는 private가 디폴트로 설정되며 이 디폴트를 바꾸는건 불가능합니다.

즉 enum의 생성자는 모두 private입니다.


 

생성자의 호출타이밍은 우리가 정확하게 예측하기는 힘들지만 확실한건

저희가 호출하는건 불가능하고 이미 Trump가 필요한 순간에 생성자가 자동으로 호출하게됩니다.


 

생성자의 호출타이밍을 알기위해서 한줄의 코드를 추가했습니다.

main메소드는 위의 클럽을 출력하는 메소드를 그대로 토시하나 바꾸지 않고 사용했습니다.

저희가 사용한건 클럽 하나였지만 이미 생성자는 4번 호출이되고 더이상 호출되지 않습니다.


저 생성자가 값으로 정수를 받았지만 사실 정수를 받았다고 끝이 난게 아닙니다.

이 정수를 식별자중 하나로 쓰고싶다면 그 정수를 각각의 enum이 가지고 있어야합니다.

그러기 위해서 존재하는게 int val입니다.

각각의 생성자는 정수를 받으며 그 정수를 멤버로 사용할 수 있습니다.

또한 set과 get을 사용해서 실행시간동안 바꾸거나 값을 확인하는것 역시 가능합니다.


여기서 궁금한점이 만약 실행시간에서 값을 변경하게 되면 어떻게 될까요?

그 궁금증을 풀기위해서 아래의 예제를 한번 실행해보도록합시다.

보시면 처음에는 CLUB이 15였지만  한번 2로 수정하면 어디에서 접근을 하던 새로만들던 간에

무조건 값이 2로 고정이 됩니다.



 


enum은 더 나아가서 각각의 토큰마다 파라메터 갯수를 다르게 줄 수도 있습니다.

그 경우 생성자를 그 파라메터 수에 맞게 늘려주면 장땡입니다.

전부다 두개씩을 줄 수도 있지만 한개만 두개를 줄 수도 있고 한개만 3개를 줄 수도 있는 것이죠.


 

또한 enum은 class와 interface등과는 다르게 ==연산자를 사용해서 비교할 수 있습니다.

equals만 써야하는 다른 객체형들과달리 enum객체는 ==연산을 사용할 수 있는 것이죠.


3.java.lang.Enum

이 패키지는 모든 enum의 조상입니다.

모든 class의 조상이 java.lang.Object이듯이 모든 enum의 조상은 java.lang.Enum이죠.

또 신기하게도 Enum은 abastract class로 구현되어 있으므로 Enum클래스는 Object의 후손이기도 합니다.

모든 enum의 조상은 Object이며 또한 Enum이므로 Obeject클래스가 지원하는 메소드들을 모조리 사용가능하며

또한 Enum이 지원해주는 메소드 역시 사용기 가능합니다. 그 목록은 아래와 같습니다.


3-1.getDeclaringClass

 

이 메소드는 열거형의 클래스 자체를 반환하는 메소드입니다.

Class 클래스로 반환하는데 아직 Class 클래스는 하지 않았으므로 이런 기능이 있다만 알아 두시면 됩니다.


3-2.name()

 

이 메소드는 상수의 토큰 그 자체를 반환합니다. 즉 Trump.CLUB이 있다면 CLUB을 반환하는거죠.

보통 name 메소드를 안쓰고 토큰만써도 name이 반환되기에 잘 사용되진 않습니다/


3-3.ordinal()

 

이 메소드는 사용하면 지금 사용중인 토큰이 몇번째 토큰인지를 알아낼 수 있습니다.


3-4.valueOf(String name)

 

이 메소드는 열거형을 쓰게된다면 굉장히 많이 쓰는 메소드인데 토큰의 이름으로 해당 상수를 추적할 수 있습니다.


 

보시다시피 Trump형 enum에서 CLUB에 해당하는 값의 숫자를 알고싶을경우 다음과 같은 방법을 사용할 수 있습니다.


4.열거형 추상 메소드

열거형에도 추상메소드를 적용할 수 있습니다. 또한 열거형에도 익명 enum을 사용할 수 있습니다.

이 방식은 조금만 생각해보면 어떻게 할지 쉽게 감을 잡을 수 있습니다.


 

보시면 마지막으로 PrintTrump를 추상메소드로 선언한것을 알 수 있습니다.

추상메소드로 선언즉시 모든 열거형 토큰들에 빨간줄이 끄입니다.

왜냐하면 추상메소드를 구현해줘야하기 때문이죠.

따라서 이들은 모두 익명클래스를 써서 구현해줘야합니다.


 

이런식으로 모두 구현해주면 되겠습니다.


5.마치며

이번엔 열거형을 했는데요, 자바에서 열거형있으면 좋겠다고 빼애액거려서

JDK1.5버전에서 기껏해서 만들어줬는데 이미 사람들은 class로만드는게 익숙한지

사실 코드 보다보면 잘 보이진 않습니다.

그러나 enum도 써보면 많은 도움이 될것 같애요.

반응형

'Study > Java' 카테고리의 다른 글

열거형 enums  (0) 2018.03.19
Collection Framwork 1.3 LinkedList  (0) 2018.03.05
Collection Framework 1.2 ArrayList  (0) 2018.03.05
java.time 패키지를 이용하여 달력 만들기  (0) 2018.03.05
Collection Framework 1.7 Comparator, Comparable  (0) 2018.02.26
반응형

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