본문 바로가기
[JAVA]/JAVA 기본

[JAVA] 제네릭 & 와일드 카드

by 황원용 2022. 9. 14.
728x90

📌 제네릭(Generic)

  • 제네릭이란 클래스나 메서드를 작성할 때, 타입을 구체적으로 지정하지 않고 추후에 지정하고 변경할 수 있도록 타입 매개변수를 이용하여 타입을 일반화하는 것을 의미한다.

 

 

 

제네릭 클래스

class Box<T> {
    private T item1; // O
    static T item2; // X
}
public class Main {
    public static void main(String[] args) {
        Box<String> Box1 = new Box<>("this is Box");
        Box<Integer> Box2 = new Box<>(1);
        Box<Double> Box3 = new Box<>(1.11);
        // 제네릭 클래스로 인스턴스화할 때에는 타입 매개변수에 치환될 타입을 지정해주어야 한다.
        
        System.out.println(Box1.getItem());
        System.out.println(Box2.getItem());
        System.out.println(Box3.getItem());
    }
}

class Box<T> { // T를 임의의 타입으로 사용한다. 여러개의 타입을 사용할 때는 <K, V> 등으로 사용할 수 있다.
    private T item; // T : type, K : key, V : value의 첫글자를 따 만든 변수명

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

    public T getItem() {
        return item;
    }

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

// 출력값
this is Box
1
1.11
  • 제네릭 클래스에서 클래스 변수에는 타입 매개변수를 사용할 수 없다. 클래스 변수는 모든 인스턴스가 공유하기 때문에 타입 매개변수를 사용한다면 클래스 변수의 타입이 서로 달라지게 되어 같은 변수를 공유하는 것이 아니게 되기 때문이다. 예를 들어 Box라는 클래스 변수에 타입 매개변수를 사용할 수 있다면, Box<String>으로 만든 인스턴스와 Box<Integer>로 만든 인스턴스가 공유하는 클래스 변수의 타입이 서로 달라진다.

 

interface Animal{}
class Dog implements Animal{} // (1)
class Siba extends Dog implements Animal{}; // (2)

class Example1 <T extends Dog> {
    // Example1 클래스를 인스턴스화할 때 타입으로 Dog클래스의 하위 클래스만 지정하도록 제한
    private T item;
    }
class Example2 <T extends Animal> {
    // Example2 클래스를 인스턴스화할 때 타입으로 Animal 인터페이스를 구현한 클래스만 지정하도록 제한
    private T item;
    }
class Example3 <T extends Dog & Animal> {
    // Example 클래스를 인스턴스화할 때 타입으로 특정 클래스를 상속받으면서 동시에 특정 인터페이스를 구현한 클래스만 지정하도록 제한
    private T item;
    }

public class Main {
    public static void main(String[] args) {
        Example2<Dog> DogEx = new Example2<>(); // (1)
        Example3<Siba> SibaEx = new Example3<>(); //(2)
    }
}
  • 특정 클래스를 상속받은 클래스나 특정 인터페이스를 구현한 클래스만 타입으로 지정할 수도 있다.

 

 

제네릭 메서드

class Box<T> { // (1)
    public <T> void add(T element) { // (2)     (1)의 T와 (2)의 T는 서로 다른 변수이다.
    // 제네릭 메서드의 타입 매개변수 선언은 반환타입 void 앞에서 이루어지며, 해당 매서드 내에서만 사용할 수 있다.
    }
}

 클래스 전체를 제네릭으로 선언하는 것이 아닌 클래스 내부의 특정 메서드만 제네릭으로 선언하는 경우이다.

 

 

 

📌 와일드 카드

  • 어떠한 타입으로든 대체될 수 있는 타입 파라미터이며 기호 '?'를 사용한다.
  • 와일드 카드는 Any Type이 아니라, Unknown Type이다.
<? extends T>는 상한 제한을 두는 것으로, T와 T를 상속받는 하위 클래스 타입만 타입 파라미터로 받는다.
<? super T>는 하한 제한을 두는 것으로, T와 T의 상위 클래스만 타입 파라미터로 받는다.
<?>는 모든 클래스 타입을 타입 파라미터로 받을 수 있다.
class Laptop {}

class Windows extends Laptop {}
class Macbook extends Laptop {}

class Gram extends Windows{}
class Galaxybook extends  Windows{}

class M1MacbookAir extends Macbook{}
class M2MacbookAir extends  Macbook{}

class User<T> {
    public T laptop;

    public User(T laptop) {
        this.laptop = User.this.laptop;
    }
}

class LaptopFunction {
    public static void Internet(User <? extends Laptop> user){
        System.out.println("-".repeat(30));
        System.out.println("user.laptop = " + user.laptop.getClass().getSimpleName());
        System.out.println("모든 Laptop은 인터넷이 가능합니다.");

    }public static void facetime(User <? extends Macbook> user){
        System.out.println("-".repeat(30));
        System.out.println("user.laptop = " + user.laptop.getClass().getSimpleName());
        System.out.println("모든 Mac은 페이스타임이 가능합니다.");

    }public static void macsafe(User <? extends M2MacbookAir> user){
        System.out.println("-".repeat(30));
        System.out.println("user.laptop = " + user.laptop.getClass().getSimpleName());
        System.out.println("M2칩이 탑재된 맥북에어는 맥세이프로 충전이 가능합니다.");

    }public static void game(User <? super Windows> user){
        System.out.println("-".repeat(30));
        System.out.println("user.laptop = " + user.laptop.getClass().getSimpleName());
        System.out.println("윈도우 운영체제를 가진 게이밍 노트북은 원활한 게임 플레이가 가능합니다.");

    }
}

public class Main {
    public static void main(String[] args) {
        LaptopFunction.Internet(new User<Laptop>(new Laptop()));
        LaptopFunction.Internet(new User<Windows>(new Windows()));
        LaptopFunction.Internet(new User<Macbook>(new Macbook()));
        LaptopFunction.Internet(new User<Gram>(new Gram()));
        LaptopFunction.Internet(new User<Galaxybook>(new Galaxybook()));
        LaptopFunction.Internet(new User<M1MacbookAir>(new M1MacbookAir()));
        LaptopFunction.Internet(new User<M2MacbookAir>(new M2MacbookAir()));

        LaptopFunction.facetime(new User<Laptop>(new Laptop())); // 에러
        LaptopFunction.facetime(new User<Windows>(new Windows())); // 에러
        LaptopFunction.facetime(new User<Macbook>(new Macbook()));
        LaptopFunction.facetime(new User<Gram>(new Gram())); // 에러
        LaptopFunction.facetime(new User<Galaxybook>(new Galaxybook())); // 에러
        LaptopFunction.facetime(new User<M1MacbookAir>(new M1MacbookAir()));
        LaptopFunction.facetime(new User<M2MacbookAir>(new M2MacbookAir()));

        LaptopFunction.macsafe(new User<Laptop>(new Laptop())); // 에러
        LaptopFunction.macsafe(new User<Windows>(new Windows())); // 에러
        LaptopFunction.macsafe(new User<Macbook>(new Macbook())); // 에러
        LaptopFunction.macsafe(new User<Gram>(new Gram())); // 에러
        LaptopFunction.macsafe(new User<Galaxybook>(new Galaxybook())); // 에러
        LaptopFunction.macsafe(new User<M1MacbookAir>(new M1MacbookAir())); // 에러
        LaptopFunction.macsafe(new User<M2MacbookAir>(new M2MacbookAir()));

        LaptopFunction.game(new User<Laptop>(new Laptop()));
        LaptopFunction.game(new User<Windows>(new Windows()));
        LaptopFunction.game(new User<Macbook>(new Macbook())); // 에러
        LaptopFunction.game(new User<Gram>(new Gram())); // 에러
        LaptopFunction.game(new User<Galaxybook>(new Galaxybook())); // 에러
        LaptopFunction.game(new User<M1MacbookAir>(new M1MacbookAir())); // 에러
        LaptopFunction.game(new User<M2MacbookAir>(new M2MacbookAir())); // 에러
    }
}
728x90

'[JAVA] > JAVA 기본' 카테고리의 다른 글

[JAVA] 컬렉션 프레임워크  (0) 2022.09.14
[JAVA] 예외 처리 정리  (0) 2022.09.14
[JAVA] 열거형  (0) 2022.09.13
[JAVA] 래퍼 클래스(Wrapper Class)  (0) 2022.09.13
[JAVA] 형변환 총정리  (0) 2022.09.12