[java] 제네릭

이동엽·2023년 1월 7일
0

제네릭

무엇인가?

성한 클래스 또는 메서드의 코드가 특정 데이터 타입에 얽매이지 않게 해주는 타입이다.
원래 클래스는 별도의 타입을 정해서 만든다.

//이게 원본
class Basket {
    private String item;

    Basket(String item) {
        this.item = item;
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }
}

제네릭을 사용하면
class Basket<T> {
    private T item;

    public Basket(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}
// 만약에 타입 매개변수를 여러개 사용하면 
class Basket<K,V>{}
T : type, K : key, V : Value
//하지만 변수와 메소드에 static은 못쓴다.

제네릭 사용하면 클래스 하나로 모든 타입의 데이터를 저장할 수 있는 인스턴스를 만들 수 있다.
->객체를 만들려면

Basket<String> basket1 = new Basket<String>("미리미");
Basket<Integer> baslet2 = new Basket<Integer>();
// <T>를 String,Integer으로 하고 객체생성 이라는 뜻

다형성도 적용할수 있다.

class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }

class Basket<T> {
    private T item;

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}

class Main {
    public static void main(String[] args) {
        Basket<Flower> flowerBasket = new Basket<>();
        flowerBasket.setItem(new Rose());      // 다형성 적용
        flowerBasket.setItem(new RosePasta()); // 에러
    }
}
------------------------------------------------
class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }

// 제네릭 클래스 정의 
class Basket<T> {
    private T item;

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}

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

        // 인스턴스화 
        Basket<Rose> roseBasket = new Basket<>();
        Basket<RosePasta> rosePastaBasket = new Basket<>();
    }
}

인스턴스화 할때 타입을 하위 클래스만 지정하도록 제한 하는 방법

class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }
//1. Basket 클래스를 인스턴스화 할때 Flower 클래스의 하위 클래스만 지정 제한
class Basket<T extends Flower> {
    private T item;
	
		...
}
//2. 특정 인터페이스를 구현한 클래스만 타입으로 지정할 수 있도록 제한.
interface Plant { ... }
class Flower implements Plant { ... }
class Rose extends Flower implements Plant { ... }

class Basket<T extends Plant> {
    private T item;
	
		...
}
//3. 특정 클래스를 상속받으면서 동시에 특정 인터페이스를 구현한 클래스만 타입으로 제한할때 
//&를 사용
interface Plant { ... }
class Flower implements Plant { ... }
class Rose extends Flower implements Plant { ... }

class Basket<T extends Flower & Plant> { // (1)
    private T item;
	
		...
}

class Main {
    public static void main(String[] args) {
    
        // 1번 인스턴스화 
        Basket<Rose> roseBasket = new Basket<>();
        Basket<RosePasta> rosePastaBasket = new Basket<>(); // 에러
        //2번 인스턴스화
        Basket<Flower> flowerBasket = new Basket<>();
        Basket<Rose> roseBasket = new Basket<>();
        //3번 인스턴스화
        Basket<Flower> flowerBasket = new Basket<>();
        Basket<Rose> roseBasket = new Basket<>();
    }
}

제네릭 메소드

클래스 전체 말고, 클래스 내부의 특정 메소드만 제네릭으로 선언한것

class Basket{
	public <T> void add(T element) {
				...
		}
}

단 알아야 할점

class Basket<T>{//1번 여기 매개변수 타입 T
	publc <T> void add(T element){ 2번여기 매개변수 타입 T
    }
}
---
이젠 메소드 타입 매개변수는 static 메소드에서도 선언 해서 사용할수 있다.
class Basket{
	static <T> int setPrice(T element){
    }
}

저 1번 2번은 서로 다른 별개의 것이다.
이름만 T라고 같지 서로 다른 매개변수 타입이다.

클래스명 옆에서 선언한 타입 매개변수는 클래스가 인스턴스화될 때 타입이 지정된다.
하지만 제네릭 메소드 타입 지정은 메소드가 호출 될때 된다.

Basket<String> basket = new Bakset<>();
basket.<Integer>add(10);
basket.add(10);//이렇게 타입 지정을 생략도 할수 있다.

length()와 같이 String 클래스 메소드는 사용못하지만
Object클래스 메소드는 사용할수 있다

class Basket {
    public <T> void print(T item) {
        System.out.println(item.length()); // 불가
        System.out.println(item.equals("Kim coding")); // 가능
    }
}

와일드 카드

어떠한 타입으로든 대체될수 있는 타입 파라미터.
기호는 ?

<? extends T>
<? super T>
는 T와 T를 상속 받는 하위 클래스 타입만 타입 파라미터로 받을 수 있도록 지정한다. 는 T와 T의 상위 클래스만 타입 파라미터로 받도록 한다.
profile
씨앗

0개의 댓글