티스토리 뷰

1. 제네릭스

1-1. 제네릭스(Generics)란?

💡 데이터의 타입을 일반화한다는 의미를 가진다.
제네릭 클래스는 제네릭 타입(T, E, K, V)을 활용하여 하나의 클래스로 해당 제네릭 타입에 변화를 줘서 제네릭 클래스의 인스턴스를 다양한 타입을 지닌 인스턴스로 활용
public class GenericTest<T> {

	private T value;
	
	public T getValue() {
		return value;
	}
	
	public void setValue(T value) {
		this.value = value;
	}
}
// 제네릭 클래스의 T(타입)에 해당하는 부분이 모두 Integer로  변환된다.
GenericTest<Integer> gt = new GenericTest<Integer>();

1-2. 제네릭스를 사용하는 이유

💡 구현의 편의성
하나의 클래스만 작성해도 여러 타입의 필드 값을 가진 클래스로 변형해서 다룰 수 있다.
💡 자료형의 안정성이 높다.
타입을 명확히 알고 쓰기 때문에 해당 제네릭 클래스의 필드 타입이나 메소드의 매개변수나 반환형을 알고 사용
package com.ohgiraffers.section01.generic;

public class Application {
    public static void main(String[] args) {

        /* 수업목표. 제네릭(generic)에 대해 이해할 수 있다. */
        MyGenericTest mgt = new MyGenericTest();

        mgt.setValue("Hello World!");
        mgt.setValue(1);
        mgt.setValue(3.14);

        System.out.println(mgt.getValue());
        Object result = mgt.getValue();     // double 형으로 못받고 Object 로 받는다.
        double privitiveResult = (Double)result;
//        String privitiveResult = (String)result;    // (Double)형으로 다운캐스팅을 해야하지만
//                                                    // (String)으로 다운캐스팅도 컴파일 시점에 가능해지고
//                                                    // 이는 런타임 에러를 발생시킨다.
//                                                    // (Object를 활용한 것은 자료형이 안전하지 않다.)
//                                                    // 자료형이 안전하지 않다. 보장하지 않는다.

//        GenericTest<Integer> gt1 = new GenericTest<Integer>();
        GenericTest<Integer> gt1 = new GenericTest<>(); // 객체의 생성자 부분에는 빈 다이아몬드 연산자도 허용 가능

//        String strResult = (String)gt1.getValue();      // 컴파일 시점에 컴파일 에러로 인해 타입을 체크할 수 있다. 오류 발생!
//        String strResult1 = gt1.getValue() + "";        // 이런 식으로 문자열 변경할 수 있다.
        int intResult = gt1.getValue();                 // 다운캐스팅을 고려하지 않아도 된다.

//        gt1.setValue("피카츄");
        gt1.setValue(10);               // gt1은 Integer 전용이다...

        /* 필기.
        *   제네릭 클래스는 다양한 자료형으로 변할 수 있어 클래스 하나만으로 활용가치가 높아진다.(구현의 편의성)
        *   매개변수나 반환형도 제네릭 타입으로 지정되어 명확히 해당 타입에 대해 처리할 수 있다.(타입의 안정성)
        *  */

    }
}
package com.ohgiraffers.section01.generic;

/* 필기.
*   제네릭 클래스의 다이아몬드 연산자(<>)에 들어갈 수 있는 4가지 타입
*   1. E: Element
*   2. T: Type
*   3. K: Key
*   4. V: Value
*  */
public class GenericTest<T> {
    private T value;

    public GenericTest() {
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}
package com.ohgiraffers.section01.generic;

/* 설명. 다형성 및 boxing에 의해 어떤 값이든 호환되는 클래스 */
public class MyGenericTest {

    private Object value;

    public MyGenericTest() {
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }
}

2. 와일드 카드

2-1. 와일드카드(Wildcard)란?

💡 제네릭 클래스의 인스턴스를 유연하게 활용하기 위한 문법.
메소드의 매개변수로 받을 시 타입을 원하는 만큼으로 제한하는 것으로 불특정한 제네릭 클래스 타입을 조금 더 활용할 수 있다.

<?>: 모든 타입을 허용
<? extends T>: T 타입 또는 T의 하위 타입을 허용
<? super T>: T 타입 또는 T의 상위 타입을 허용

 

extend.run
package com.ohgiraffers.section02.extend.run;

import com.ohgiraffers.section02.extend.vo.*;

public class Application1 {
    public static void main(String[] args) {

        /* 수업목표. extends 키워드를 사용하여 특정 타입만 제네릭 타입으로 사용하도록 제한할 수 있다. */
        /* 설명. Rabbit이거나 Rabbit의 자식 타입이 아닌 타입으로 제네릭 타입을 지정하면 컴파일 에러가 발생한다. */
//        RabbitFarm<Animal> farm1 = new RabbitFarm<>();
//        RabbitFarm<Mammal> farm2 = new RabbitFarm<>();
//        RabbitFarm<Snake> farm3 = new RabbitFarm<>();

        /* 설명. Rabbit 또는 Rabbit의 자식 타입으로는 인스턴스 생성이 가능하다.(<T extends Rabbit>) */
        RabbitFarm<Rabbit> farm4 = new RabbitFarm<>();          // 다형성 적용 가능한가??????????????
        RabbitFarm<Bunny> farm5 = new RabbitFarm<>();
        RabbitFarm<DrunkenBunny> farm6 = new RabbitFarm<>();

        farm4.setAnimal(new Rabbit());
        farm4.getAnimal().cry();
        farm4.setAnimal(new Bunny());
        farm4.getAnimal().cry();        // 동적 바인에 의해 반환형이 Rabbit의 cry()가 아닌 실제 객체인 Bunny의 cry()가 실행됨

        farm5.setAnimal(new Bunny());
        farm5.getAnimal().cry();

        farm6.setAnimal(new DrunkenBunny());
        farm6.getAnimal().cry();

    }
}

// 실행 결과
토끼가 울음소리를 냅니다. 끾끾!
바니바니 바니바니 당근당근!

바니바니 바니바니 당근당근!

바니바니 빠니뽜니 당근 당@#@?!?
package com.ohgiraffers.section02.extend.run;

import com.ohgiraffers.section02.extend.vo.*;

public class Application2 {
    public static void main(String[] args) {

        /* 수업목표. 와일드카드에 대해 이해할 수 있다. */
        WildCardFarm wildCardFarm = new WildCardFarm();
        wildCardFarm.anyType(new RabbitFarm<Rabbit>(new Rabbit()));
        wildCardFarm.anyType(new RabbitFarm<Bunny>(new Bunny()));
        wildCardFarm.anyType(new RabbitFarm<DrunkenBunny>(new DrunkenBunny()));

//        wildCardFarm.extendsType(new RabbitFarm<Rabbit>(new Rabbit()));
        wildCardFarm.extendsType(new RabbitFarm<Bunny>(new Bunny()));
//        wildCardFarm.extendsType(new RabbitFarm<DrunkenBunny>(new DrunkenBunny()));

        wildCardFarm.superType(new RabbitFarm<Rabbit>(new Rabbit()));
        wildCardFarm.superType(new RabbitFarm<Bunny>(new Bunny()));
//        wildCardFarm.superType(new RabbitFarm<DrunkenBunny>(new DrunkenBunny()));
    }
}

// 실행 결과
토끼가 울음소리를 냅니다. 끾끾!
바니바니 바니바니 당근당근!
바니바니 빠니뽜니 당근 당@#@?!?

바니바니 바니바니 당근당근!

토끼가 울음소리를 냅니다. 끾끾!
바니바니 바니바니 당근당근!
extend.vo
package com.ohgiraffers.section02.extend.vo;

public interface Animal {
}
package com.ohgiraffers.section02.extend.vo;

public class Mammal implements Animal {
}
package com.ohgiraffers.section02.extend.vo;

public class Rabbit extends Mammal {

    public void cry() {
        System.out.println("토끼가 울음소리를 냅니다. 끾끾!");
    }
}
package com.ohgiraffers.section02.extend.vo;

public class Bunny extends Rabbit{
    @Override
    public void cry() {
        System.out.println("바니바니 바니바니 당근당근!");
    }
}
package com.ohgiraffers.section02.extend.vo;

public class DrunkenBunny extends Rabbit{
    @Override
    public void cry() {
        System.out.println("바니바니 빠니뽜니 당근 당@#@?!?");
    }
}
package com.ohgiraffers.section02.extend.vo;

public class RabbitFarm<T extends Rabbit> {
    private T animal;

    public RabbitFarm() {
    }

    public RabbitFarm(T animal) {
        this.animal = animal;
    }

    public T getAnimal() {
        return animal;
    }

    public void setAnimal(T animal) {
        this.animal = animal;
    }
}
package com.ohgiraffers.section02.extend.vo;

public class Reptile implements Animal {
}
package com.ohgiraffers.section02.extend.vo;

public class Snake extends Reptile {
}
package com.ohgiraffers.section02.extend.vo;

/* 설명.
*   와일드카드(wildcard)
*    제네릭 클래스 타입의 객체를 메소드의 매개변수로 받을 때 타입 변수를 제한할 수 있다.
*    <?>: 제한 없음
*    <? extends Type>: 와일드카드의 상한 제한(Type과 Type의 후손을 이용해 생성된 제네릭 인스턴스만 가능) // 예시에서 제네릭 인스턴스는 토끼농장
*    <? super Type>: 와일드카드의 하한 제한(Type과 Type의 부모를 이용해 생성된 제네릭 인스턴스만 가능)
*  */
/* 설명. 제네릭 타입을 활용하는 기능을 포함한 클래스 */
public class WildCardFarm {

    /* 설명. 어떤 타입의 RabbitFarm(제네릭 타입)이 와도 상관 없다. */
    public void anyType(RabbitFarm<?> farm) {       // 토끼가 뛰어노는 토끼 농장이면 상관 없다.
        farm.getAnimal().cry();
    }

    /* 설명. RabbitFarm 중에서도 Buuny 또는 하위 타입이 있는 RabbitFarm만 가능 */
    public void extendsType(RabbitFarm<? extends Bunny> farm) {
        farm.getAnimal().cry();
    }

    /* 설명. RabbitFarm 중에서도 Bunny 또는 상위 타입이 있는 RabbitFarm만 가능 */
    public void superType(RabbitFarm<? super Bunny> farm) {
        farm.getAnimal().cry();
    }
}

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함