컬렉션_제네릭

김예인·2023년 5월 2일

백엔드 공부일지

목록 보기
15/43
post-thumbnail

제네릭 (Generic)

작성한 클래스 또는 메서드의 타입을 지정하지 않고, 추후에 지정할 수 있도록 일반화해 두는 것


📒 제네릭 클래스


| 정의

1. class Basket<T> { ... } // T: 타입 매개변수 (임의의 문자)

2. class Basket<K, V> { ... } // 여러개의 타입 매개변수 선언

🔍 모든 인스턴스가 공유하는 static 이 붙은 클래스 변수 또는 메서드에는 타입 매개변수 사용 불가!


| 사용

  • 제네릭 클래스를 인스턴스화할 땐 타입 지정
  • 기본 타입(int, double) 이 아닌 래퍼 클래스( Integer , Double ) 활용
Basket<String>  basket1 = new Basket<>("제네릭");
Basket<Integer> basket2 = new Basket<>(10);
Basket<Double>  basket2 = new Basket<>(3.14);

// new Basket<타입> 생략 가능 (참조변수의 타입으로부터 유추)
  • 다형성 적용 가능
class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }

class Basket<T> { ... }

class Main {
    public static void main(String[] args) {
    
        Basket<Flower> flowerBasket = new Basket<>(); // 제네릭 클래스 Basket의 타입 매개변수: Flower
        flowerBasket.setItem(new Rose());      // 다형성 적용 (상속받고 있으므로)
        flowerBasket.setItem(new RosePasta()); // 에러 (아무런 관계가 없으므로)
    }
}

| 제한된 제네릭 클래스

🧷 extends 키워드를 사용하여

  1. 특정 클래스를 상속받은 클래스만 타입으로 지정할 수 있도록 제한
class Basket<T extends Flower> { ... }
  1. 특정 인터페이스를 구현한 클래스만 타입으로 지정할 수 있도록 제한
interface Plant { ... }
class Flower implements Plant { ... }
class Rose extends Flower implements Plant { ... }

** class Basket<T extends Plant> { ... }

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

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

🧷 & 키워드를 사용하여

  1. 과 2. 를 동시에 적용
class Basket<T extends Flower & Plant> { ... }

📒 제네릭 메서드

클래스 내부의 특정 메서드만 제네릭으로 선언 가능

| 사용

  • 반환타입 앞에서 매개 변수 선언
  • 클래스 타입 매개 변수와 달리, static 메서드에서도 선언하여 사용 가능
  • 해당 메서드 내에서만 선언한 타입 매개 변수를 사용 가능
  • 제네릭 메서드의 타입 매개 변수는 제네릭 클래스의 타입 매개 변수와 동일 변수명을 사용하더라도 서로 다른 타입 매개 변수로 간주
    - 이유 : 제네릭 클래스 타입 매개변수는 클래스가 인스턴스화될 때 타입이 지정되지만, 제네릭 메서드의 타입 지정은 메서드가 호출될 때 지정
class Basket<T> { // 1 : 여기에서 선언한 타입 매개 변수 T와 
		...
		public <T> void add(T element) { // 2 : 여기에서 선언한 타입 매개 변수 T는 서로 다른 것
				...
		}
}
  • 같은 이유로 정의 시점에 실제 어떤 타입이 입력되는지 알 수 없기 때문에 length()와 같은 String 클래스의 메서드는 제네릭 메서드를 정의하는 시점에 사용 불가
    단, equals(), toString() 등의 Object 클래스의 메서드는 사용 가능
class Basket {
    public <T> void print(T item) {
        System.out.println(item.length()); // 불가
    }
}

📒 와일드카드

어떠한 타입으로든 대체될 수 있는 타입 파라미터, 기호 ? 로 사용 가능

// 일반적으로 extends와 super 키워드를 조합하여 범위를 지정해 사용
  
<? extends T> : 상한 제한, TT를 상속받는 하위 클래스 타입만 타입 파라미터로 받도록 지정
<? super T> : 하한 제한, TT의 상위 클래스만 타입 파라미터로 받도록 지정
<?> = <? extends Object> : 모든 클래스 타입을 타입 파라미터로 받을 수 있음
profile
백엔드 개발자 김예인입니다.

0개의 댓글