본문 바로가기
JAVA/객체지향

제네릭,열거형

by chogigang 2023. 2. 24.

제네릭

 

다양한 타입의 객체를 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크,객체나입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄일수있게 도와줍니다

 

 

 

제네릭의 장점

 

  • 타입 안전성을 제공
  • 타입체크와 형변환을 생략할 수 있으므로 코드가 간결

제네릭 클래스의 선언

 

제네릭 타입은 클래스와 메서드에서 선언할수 있습니다. 

 

클래스에서 제네릭 선언

class Box<T> {
    T item;
    void setItem(T item) {this.item = item;}
    T getItem() {return item}
    
}

 

상황에 맞게 의미있는 문자를 선택해서 사용하는 것이 좋습니다

 

기호의 종류만 다를 뿐 '임의의 참조형 타입'을 의미한다는 것은 모두 같습니다.

 

Box<String> b = new Box<String>(); //타입 T대신, 실제 타입을 지정
    b.setItem(new Object ());//에러. String 이외의 타입은 지정불가
    b.setItem("ABC"); // OK String 타입이므로 가능
    String item = (String) b.getItem//형 변환이 필요없음

 

Box<Object> b = new Box<Object>();
    b.setItem(new Object ());//경고발생 안함
    b.setItem("ABC"); //경고발생안함
 

 

제네릭 용어

 

 

 

 

 

Box<T> - 제네릭 클래스. 'T의 Box' 또는 'T Box'라고 읽습니다.

T - 타입 변수 또는 타입 매개변수(T는 타입 문자)

Box - 원시 타입(raw type)

 

iterator<E>

 클래스를 작성할 때, Object타입 대신 T와 같은 타입 변수를 사용합니다.

 

 

HashMap<K, V>

여러 개의 타입 변수가 필요한 경우 ( , ) 를 구분자로 선언 해야합니다.

 

 

제네릭의 제한 

지네릭 클래스 Box의 객체를 생성할 때, 객체별로 다른 타입을 저장하는 것은 적절합니다

제네릭은 인스턴스별로 다르게 동작하도록 하려고 만든 기능입니다.

Box<Apple> appleBox = new Box<Apple>(); //ok Apple 객체만 저장 가능
    Box<Grape> grapeBox = new Box<Grape>(); //ok Grape 객체만 저장가능

 그러나 모든 객체에 대해 동일하게 동작해야하는 static멤버에 타입 변수 T를 사용할수 없습니다 T는 인스턴스변수로

static 멤버는 인스턴스 변수를 참조할 수 없습니다.

 

제네릭 타입의 배열을 생성하는 것도 허용되지 않습니다.

 

 

제오ㅓ한된 제네릭 클래스

 

extends를 사용하면 특정 타입의 자손들만 대이발 수 있게 제한할 수 있습니다.

 

class FruitBox<T extends Fruit> {// Fruit 의 자손만 타입으로 지정 가능
        ArrayList<T> list = new ArrayList<T>();
    ....
}

 

와일드 카드

 

하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능합니다.

<? extends T> 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T> 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> 제한 없음. 모든 타입이 가능

제네릭 클래스와 달리 와일드 카드에는 &를 사용할수 없습니다 <? extends T&E>와 같이 할 수 없습니다.

 

static Juice makeJuice(FruitBox <? extends Fruit> box){
        String tmp = "";
        for(Fruit f : box.getList()) tmp+= f + "";
        return  new Juice (tmp);

}
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();//T와 그 자손
    FruitBox<Apple> appleBox = new FruitBox<Apple>();//T와 그자손
}

 

제네릭 메서드

제네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)

메서드를 호출할 때마다 타입을 대입해야 합니다. (대부분 생략 가능)

메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가합니다.

 

제네릭 타입의 형변환

제네릭 타입과 원시 타입 간의 형변환은 바람직 하지 않습니다. (경고 발생)

와일드 카드가 사용된 제네릭 타입으로는 형변환 가능 합니다.

 

제네릭 타입의 제거

컴파일러는 제네릭 타입을 이용해서 소스파일을 체크 하고 필요한 곳에 형변환을 넣어줍니다

그리고 제네릭 타입을 제거 합니다.

 

열거형

 

서로 관련된 상수를 같이 묶어 놓은것입니다.

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

열거형 상수간의 비교에는 '=='를 사용할 수 있습니다 equals()가 아닌 '=='로 비교가 가능한것은

그만큼 빠른 성능을 제공한다는 이야기 입니다 그러나 ( '>','<') 같은 비교연산자는 사용 할수 없고

compareTo()는 사용가능 합니다

 

 

==

compareTo() 

같으면 0

왼쪽이 크면 양수

오른쪽이 크면 음수

 

 

 

// 열거형 정의
enum Direction {EAST, WEST, SOUTH, NORTH}

class Unit{
    int x, y;
    Direction dir; // 열거형을 인스턴스로 생성

    void init(){
        dir = Direction.EAST;

        if (dir == Direction.EAST){ //열거형은 ==으로 비교가능
            x++;
        }
        else if (dir > Direction.WEST){ //열거형은 비교연산 사용 불가
        }
        else if (dir.compareTo(Direction.WEST) > 0){ // compateTo로 비교
        }
    }
}

 

 

모든 열거형의 조상

 

 

열거형 멤버 추가

Enum Class에 정의된 oridn()이 열거형 상수가 정의된 순서를 반환합니다 (0부터1,2,3) 하지만

이 값을 열거형 상수에 값으로 사용하지 않는게 좋습니다

// 열거형 정의
enum Direction {EAST, WEST, SOUTH, NORTH}

class Unit{
    int x, y;
    Direction dir; // 열거형을 인스턴스로 생성

    void init(){
        dir = Direction.EAST;

        if (dir == Direction.EAST){ //열거형은 ==으로 비교가능
            x++;
        }
        else if (dir > Direction.WEST){ //열거형은 비교연산 사용 불가
        }
        else if (dir.compareTo(Direction.WEST) > 0){ // compateTo로 비교
        }
    }
}

열거형에 추상메서드

 

    // 열거형으로 운송수단을 선언했다.
// 각 운송수단마다 요금이 다르기 때문에 요금을 계산하는 추상메서드를 선언해야한다.
    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; // protected로 해야 각 상수에서 접근가능
        //생성자  
        Transportation(int basicFare) { // private Transportation(int basicFare) {
            BASIC_FARE = basicFare;
        }

        public int getBasicFare() { return BASIC_FARE; }
        // 추상메서드 선언
        abstract int fare(int distance); // 거리에 따른 요금 계산
    }

그냥 참고만 합시다.

'JAVA > 객체지향' 카테고리의 다른 글

람다식  (0) 2023.02.25
프로세스와 쓰레드  (0) 2023.02.24
래퍼 클래스,number클래스,문자열을 숫자로 변환  (0) 2023.02.23
String클래스  (0) 2023.02.23
hashCode(),toStirng()  (0) 2023.02.23