21.01.19-40일차

👸 지네릭스(Generics)

  • 컴파일시 타입을 체크해 주는 기능(compile-time type check)
  • 객체의 타입 안정성을 높임, 형변환의 번거로움을 줄여줌
  • 타입체크와 형변환을 생략할 수 있으므로 코드가 간결

🤴 타입변수

  • 클래스를 작성할 때, Object타입 대신 타입 변수(E)를 선언해서 사용
    (변수 이름은 아무거나 써도 상관없다)
ex>
public class ArrayList<E> extends AbstractList<E> {
	private transient E[] elementData;
    public boolean add(E o) { /* 내용 생략 */}
    public E get(int index) { /* 내용 생략 */}
}

🤴 지네릭스 용어

Box<T>  지네릭 클래스. 'T의 Box' 또는 'T Box'라고 읽는다.
  T	타입 변수 또는 매개변수.(T는 타입 문자)
  Box	원시 타입(raw type)

🤴 지네릭 타입과 다형성

  • 참조 변수와 생성자의 대입된 타입은 일치해야 한다.
ArrayList<Tv>	    list = new ArrayList<Tv>(); // 일치
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

🤴 제한된 지네릭 클래스

  • extends로 대입할 수 있는 타입을 제한
class FruitBox<T extends Fruit>{ // Fruit의 자손만 타입으로 지정가능
   ArrayList<T> list = new ArrayList<T>();
   ...
}
-
FruitBox<Apple> appleBox = new FruitBox<Apple>(); // OK
FruitBox<Toy> appleBox = new FruitBox<Toy>(); // 에러. Toy는 Fruit의 자손X.
  • 인터페이스인 경우에도 extends를 사용(implements 사용X)
interface Eatable{}
calss FruitBox<T extends Eatable> {...}

🤴 지네릭스의 제약

  • 타입 변수에 대입은 인스턴스 별로 다르게 가능
Box<Aapple> appleBox = new Box<Apple>(); // Ok. Apple객체만 저장가능
Box<Grape> appleBox = new Box<Grape>(); // Ok. Grape객체만 저장가능
  • static 멤버에 타입 변수 사용불가
    (static멤버는 모든 인스턴스에 공통)
class Box<T> {
	static T item; // 에러
    	static int compare(T t1, T t2) {...} // 에러
}
  • 배열 생성할 때 타입 변수 사용불가.
    (타입 변수로 배열 선언은 가능)
class Box<T>{
	T[] itemArr; // Ok. T타입의 배열을 위한 참조변수
   	 ...
   	T[] toArray(){
    	    T[] tmpArr = new T[itemArr.length]; // 에러. 지네릭 배열 생성불가
            					// new 연산자 다음에 T 쓸 수 없다.
    }
}

🤴 와일드 카드 <?>

  • 하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
    <? extends T> 와일드 카드의 상한 제한. T와 그 자손들만 가능
    <? super T> 와일드 카드의 하한 제한. T와 그 조상들만 가능
    <?> 제한 없음. 모든 타입이 가능. <? extends Object>와 동일
ex>
ArrayList<? extends Product> list = new ArrayList<Tv>(); // Ok
ArrayList<? extends Product> list = new ArrayList<Audio>(); // Ok
ArrayList<Product> list = new ArrayList<Tv>(); // 에러. 대입된 타입 불일치
  • 메서드의 매개변수에 와일드 카드를 사용

🤴 지네릭 메서드

  • 지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
    static <T> void sort(List<T> list, Comparator<? super T> c)
  • 클래스의 타입 매개변수<T>메서드의 타입 매개변수 <T>별개
class FuritBox<T>{ // 지네릭 클래스
	...
    static<T> voic sort(List<T> list, Comparator<? super T> c){ // 지네릭 메서드
    }
}
  • 메서드를 호출할 때마다 타입을 대입해야함(대부분 생략 가능)
  • 메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가

🤴 지네릭 타입의 형변환

  • 지네릭 타입과 원시 타입 간의 형변환은 바람직 하지 않다(경고 발생)
Box<Object> obj = null;
Box box = (Box)objBox; // Ok. 지네릭 타입 -> 원시 타입. 경고발생
objBox = (Box<Object>)box; // OK. 원시 타입 -> 지네릭 타입. 경고발생
  • 와일드 카드가 사용된 지네릭 타입으로는 형변환 가능

🤴 지네릭 타입의 제거

  • 컴파일러는 지네릭 타입을 제거하고, 필요한 곳에 형변환을 넣는다.
  1. 지네릭 타입의 경계(bound)를 제거
  2. 지네릭 타입 제거 후에 타입이 불일치하면, 형변환을 추가
  3. 와일드 카드가 포함된 경우, 적절한 타입으로 형변환 추가


👶 출처

자바의 정석 책 & 유튜브

좋은 웹페이지 즐겨찾기