주니 개발 도서관

경험 및 후기

[영상후기] 제네릭

주니홍 2022. 7. 11. 04:51

https://www.youtube.com/watch?v=n28M8iryFPw 

 

제네릭의 정의

다양한 타입의 객체들을 다루는 메서드나 클래스에

컴파일 시의 타입 체크를 해주는 기능

 

컴파일이란

사람이 이해하는 단어를 컴퓨터가 이해할 수 있는 언어로 바꿔주는 과정

 

컴파일의 효과

객체의 타입 안정성을 높이고, 형변환의 번거로움이 줄어든다

 

public class Box<T> { }

T = 타입 매개변수

Box<T> = 제네릭 클래스

 

public class Box<T> {
	List<T> items = New ArrayList<>();
    
    public void add(T item) {
    	items.add(item);
    }
}

Box<T> 제네릭 클래스를 만들어보았다

 

 

public static void main(String[]args) {
	Box<String> box = new Box<String>();
}

제네릭클래스에 타입매개변수로 String을 만들어 보낸다면

 

public class Box<String> {
	List<String> items = New ArrayList<>();
    
    public void add(String item) {
    	items.add(item);
    }
}

T 부분이 String으로 자동으로 형변환 되어 사용된다

 

 

제네릭을 쓰면 뭐가 좋은가!

  • 강력한 타입 체크를 해준다
  • 형변환을 하지 않아도 된다

 

제네릭 사용법

참조변수와 생성자에 대입된 타입이 일치해야한다!

Box<Apple> appleBox = new Box<Apple>(); O

Box<Grape> grapeBox = new Box<Grape>(); O

Box<Fruit> FruitBox = new Box<Apple>(); X
// Apple 이 Fruit를 상속해도 불가능!!

 

제네릭 클래스가 상속관계인 것은 괜찮다

Box<Fruit> fruitBox = new FruitBox<Fruit>(); O
// Box를 상속받는 클래스인 FruitBox 가능!

List<Fruit> fruitBox = new ArrayList<Fruit>(); O
// List를 상속받는 클래스인 ArrayList 가능!

Box<Fruit> grapeBox = new FruitBox<Apple>(); X
// 단, 여전히 대입되는 타입은 같아야함!!

 

 

 

제한된 제네릭

public class Box<T extends Fruit> {
	List<T> items = New ArrayList<>();
    
    public void add(T item) {
    	items.add(item);
    }
}

T는 어떤 타입이든 들어올 수 있지만

Fruit를 상속받은 타입만 들어올 수  있는 것!

 

 

 

타입 매개변수를 이렇게 표기하는 것은 '관례'이다

  • T  -  Type
  • E  -  Element (요소)
  • K  -  Key
  • V  -  Value
  • N  -  Number
  • S, U, V ..  -  2nd, 3rd, 4th types...
    (타입을 잇는 두번째타입, 세번째타입)

 

 

제네릭 메서드

public <T> T foo(List<T> list) {  }

<T>  =  타입 매개변수

T  =  리턴 타입

foo  =  메소드명

List<T> list  =  매개변수

 

일반 메서드와 다른점은 리턴타입 앞에 타입 매개변수를 사용한다는 점

 

 

 

만약 전달되는 타입 매개변수의 범위를 제한하고 싶다면?

타입매개변수 위치extends 를 해주면 된다!

public <T> T foo (List<T> list){ }

public <T> T foo (List<T extends Fruit> list){ }  X

public <T extends Fruit> T foo (List<T> list){ }  O

 

 

 

와일드 카드는 ' ? ' 기호로 표현하고

와일드 카드는 어떠한 타입도 될 수 있다

public static void print List(List<Object> list) {
	for (Object elem : list) {
    	System.out.println(elem + " ");
    }
}

public static void main(String[]args){
	List<Fruit> fruits = new ArrayList<>();
    
    MyClass.printList( fruits ); // 에러
}

에러가 나타나는 이유는 제네릭에 Object를 넣어놔서

Object형의 요소를 갖는 List만 들어올 수 있기 때문이다

 

public static void print List(List<? extends Object> list) {
	for (Object elem : list) {
    	System.out.println(elem + " ");
    }
}

와일드 카드를 사용하여 모든 타입이 들어올 수 있도록 수정

< ?  extends  Object >  를 통해 와일드 카드를 사용할 수 있다