728x90

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

객체의 타입 안정성을 높이고 형변환의 번거로움(형변환 생략가능)을 줄여줌

ArrayList<타입> list = new ArrayList<타입>();

타입 변수와 제네릭 클래스

클래스를 작성할 때 Object 타입이 아닌 제네릭 클래스(타입 변수)를 선언해서 사용

// 제네릭 클래스
MyClass<E> { // <E>,<X>,<XXX> 뭘 사용하든 상관은 없음
	//모든 타입을 지정가능
    private E 변수명;
    public boolean add(E o) {
    
    }
}

// 객체를 생성 시 실제 타입을 대입하여 사용
MyClass<Tv> myTv = new MyClass<Tv>();
//참조변수와 생성자의 타입은 항상 일치해야 함
// 실제 타입을 대입하면 기존의 E로 지정된 타입들이 다 실제타입으로 바뀜

제네릭 타입과 다형성

참조변수와 생성자의 대입된 타입은 항상 일치해야 함

제네릭 클래스 간의 다형성은 성립

매개변수의 다형성도 성립

// 참조변수와 생성자의 대입된 타입은 항상 일치해야 함
List<Tv> list = new ArrayList<Tv>();

// 제네릭 클래스 간의 다형성은 성립
List<Tv> list = new ArrayList<Tv>(); // List 타입을 모두 조상으로 가지기 때문에
List<Tv> list = new LinkedList<Tv>(); // 제네릭 타입만 일치한다면 다형성 성립

// 매개변수의 다형성도 성립
ArrayList<Product> list = new ArrayList<Product>();
list.add(new Product()); // 부모 클래스
list.add(new Tv()); // 자식 클래스
list.add(new Audio()); // 자식 클래스

Iterator<E> / HashMap<K,V>

이터레이터와 해쉬맵도 마찬가지로 타입 변수를 사용할 수 있음

// 이터레이터의 타입변수 사용
ArrayList<Student> list - new ArrayList<Student>();
Iterator<Student> it = list.iterator();
System.out.println(it.next().name); // 형변환을 할 필요가 없어짐

// 해쉬맵의 타입변수 사용
HashMap<String, Student> map = new HashMap<String, Student>();
map.put(String, new Student(Element));

제한된 제네릭 클레스

extends(상속)로 대입할 수 있는 타입을 제한

class FruitBox<T extends Fruit> { // Fruit의 자손만 타입으로 지정가능하다는 뜻
	ArrayList<T> list = new ArrayList<T>();
}

class FruitBox<T extends Fruit & Eatable> { // 인터페이스는 &로 추가
	ArrayList<T> list = new ArrayList<T>();
}

제네릭스의 제약

  • 타입 변수에 대입은 인스턴스 별로 다르게 가능
  • 정적 멤버에 타입 변수 사용 불가
  • 배열 생성할 때 타입 변수 사용불가 (T는 확정된 타입이 아니기 때문에 new 연산자 뒤에 올 수 없기 때문)
  • 타입 변수로 배열 선언 하는 경우는 가능

와일드 카드 <?>

  • 하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
  • 메서드의 매개 변수에도 사용 가능
<? extends T> // 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T> // 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> // 제한 없이 모든 타입이 가능 <? extends Object>와 동일

(매개변수 타입<와일드카드> 매개변수명) // 와일드카드에 해당하는 객체들을 매개변수로 받을 수 있음

제네릭 메소드

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

제네릭 타입의 형변환

제네릭 타입과 원시 타입 간의 형변환은 가능하지만 바람직하지 않음

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

제네릭 타입의 제거

제네릭 타입은 컴파일 단계에서 컴파일러에 의해 제거되고 필요한 곳에 형변환으로 넣어짐

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

와일드 카드가 포함된 경우에도 적절한 타입으로 형변환을 자동으로 추가

JDK의 이전 버전들에는 제네릭 타입이 없기 때문에 이전 버전들과의 호환을 위해 제거

 

'Java > Notion' 카테고리의 다른 글

애너테이션  (0) 2023.05.02
열거형(Enum)  (0) 2023.05.01
컬렉션 프레임워크 - Collections 클래스  (0) 2023.05.01
Map - HashMap / Hashtable  (0) 2023.05.01
Set - TreeSet  (0) 2023.04.30

+ Recent posts