JAVA

[지네릭스] 지네릭스

ewok 2023. 3. 15. 21:40

지네릭스(Generics)

  • 컴파일 시 타입을 체크해 주는 기능
  • 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여줌
// Tv객체만 저장할 수 있는 ArrayList를 생성
ArrayList<Tv> tvList = new ArrayLIst<Tv>();

tvList.add(new Tv());		// OK
tvList.add(new Audio());	// 컴파일 에러. Tv외에 다른 타입은 저장 불가

 

지네릭스의 장점

  1. 타입 안정성을 제공
  2. 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해짐

 

타입 변수

  • 클래스를 작성할 때, Object타입 대신 타입 변수(E)를 선언해서 사용
  • 변수 이름은 무엇을 사용해도 상관없다. (E:Element, T:Type / E 대신 T 사용가능)

 

타입 변수에 대입하기

객체를 생성 시, 타입 변수(E) 대신 실제 타입(Tv)을 지정(대입)

// 타입 변수 E 대신에 실제 타입 Tv를 대입
ArrayList<Tv> tvLIst = new ArrayLIst<Tv>();

 

 

지네릭스 용어

Box<T>, T, Box

 

지네릭 클래스 선언

 

 

지네릭 타입과 다형성

참조 변수와 생성자의 대입된 타입은 일치해야 한다.

ArrayList<Tv> list = new ArrayList<Tv>();	// OK. 일치
ArrayLIst<Product> list = new ArrayList<Tv>();	// 에러. 불일치

 

지네릭 클래스 간의 다형성은 성립(여전히 대입된 타입은 일치해야 한다.)

List<Tv> list = new ArrayList<Tv>();	// OK. 다형성. ArrayList가 List를 구현
List<Tv> list = new LinkedList<Tv>();	// OK. 다형성. LinkedList가 List를 구현

 

매개변수의 다형성도 성립

ArrayList<Product> list = new ArrayList<Product>();
list.add(new Product());
list.add(new Tv());	// OK
list.add(new Audio());	// OK

 

 

Iterator<E>

클래스를 작성할 때, Object타입 대신 T와 같은 타입 변수를 사용

 

형변환이 필요없음

 

HashMap<K,V>

여러 개의 타입 변수가 필요한 경우, 콤마를 구분자로 선언

K : Key, V : Value (꼭 K와 V를 사용해야 하는 것은 아님. 다른 문자로 대체 가능)

 

 

제한된 지네릭 클래스

extends로 대입할 수 있는 타입을 제한할 수 있다.

 

인터페이스인 경우에도 extends를 사용한다.

인터페이스를 같이 쓸 때에는 ,가 아닌 &를 사용한다. 여기에서 Fruit 클래스는 Eatable를 구현한 클래스이다.(사실 Eatable은 명시하지 않아도 된다. Fruit가 Eatable을 구현했기 때문이다.)

 

 

지네릭스의 제약

타입 변수에 대입은 인스턴스 별로 다르게 가능

 

static멤버에는 타입 변수 사용 불가 (모든 인스턴스에 공통이기 때문에)

 

배열 생성할 때 타입 변수 사용불가. 타입 변수로 배열 선언은 가능

쉽게 말해 new 연산자 뒤에 T를 사용할 수 없다.

 

 

 

와일드카드 <?>

하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능

<? extends T>를 주로 사용

 

메서드의 매개변수에 와일드카드를 사용할 수 있다.

 

 

 

지네릭 메서드

지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)

static <T> void sort(List<T> list, Comparator<? super T> c)

 

 

 

클래스의 타입 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개이다.

 

메서드를 호출할 때마다 타입을 대입해야 함(대부분 생략 가능)

메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가

 

  • 와일드카드는 하나의 참조변수로 서로 다른 타입이 대입된 여러 지네릭 객체를 다루기 위한 것이다.
  • 지네릭 메서드는 메서드를 호출할 때마다 다른 지네릭 타입을 대입할 수 있게 한 것이다.

 

지네릭 타입의 형변환

지네릭 타입과 원시 타입 간의 형변환은 바람직하지 않다.

 

와일드카드가 사용된 지네릭 타입으로는 형변환 가능

 

 

지네릭 타입의 제거

컴파일러는 지네릭 타입을 제거하고, 필요한 곳에 형변환을 넣는다.

 

1. 지네릭 타입의 경계(bound)를 제거

2. 지네릭 타입 제거 후에 타입이 불일치하면, 형변환을 추가

3. 와일드카드가 포함된 경우, 적절한 타입으로 형변환 추가