Generic
Generic
-
기본적으로 데이터 타입의 결정을 미래 시점으로 미루는 것.
-
생성시점에 원하는 타입 지정 : 다이아몬드 기호 안에 타입 매개변수 지정
-
타입 매개변수 : Generic 클래스나 메소드에서 타입으로 활용. 보통 T 표시
-
객체 생성시점에 모든 참조형 타입을 지정할 수 있다.
-
타입 추론 : 제네릭 타입 객체 생성시 new 에서 타입을 생략할 수 있다.
-
메소드와 제네릭 : 메소드는 매개변수에 인자를 전달해서 사용할 값을 결정. 제네릭은 타입 매개변수에 타입 인자를 전달해 타입을 결정.
Concept
- Generic : 데이터 타입이 나중에 결정되는 것을 의미. 클래스에서 사용할 객체의 데이터 타입을 컴파일 시점에 결정하는 것. 컴파일 시 타입 체크를 하기 때문에 런타임 에러를 방지할 수 있으며(타입안정성) 실행 시점에 다른 타입을 받아서 처리할 수있기 때문에 생산성이 늘어난다.(재사용성)
- Type Parameter : Generics에서 데이터 타입을 전달하는 변수. Generic class를 사용할 때 실제 타입으로 대체된다.
Generic Method
Concept
- Generic Method : 파라미터와 리턴타입으로 타입 파라미터를 가지는 메소드.
- Generic Method 타입추론 : 자바 컴파일러가 input type과 output type의 정보를 알고있기 때문에 타입을 메소드 실행시 명시할 필요가 없다.
- Generic Type 과 Generic Method 우선순위 : Generic Method가 Generic Type보다 우선적으로 사용된다.
public <T> Box<T> boxing(T t) { Box<T> box = new Box<T>(); box.set(t); return box;}타입 매개변수 제한하기
- extends 를 통해 제한하는 상위 타입은 Interface도 가능하다. 제한하는 타입이 클래스든 인터페이스든 상관 없이 Generic Method의 타입 제한에는 extends를 사용한다.
public class GenericTest {
public static <T extends Number> double sumSquare(T n1, T n2) { return Math.pow(n1.doubleValue(),2) + Math.pow(n2.doubleValue(),2)
}
public static <T extends Comparable<T>> T findMax(T a, T b) { return a.compareTo(b) > 0 ? a : b; }
public static void main(String[] args) { System.out.println("Sum of squares (Integer): " + sumSquare(3, 4)); System.out.println("Sum of squares (Double): " + sumSquare(2.5, 3.5)); System.out.println("Max of 10 and 20: " + findMax(10, 20)); System.out.println("Max of 'apple' and 'banana': " + findMax("apple", "banana")); }}Wildcard
- ? == <? extends Object> .
- 단순히 일반 메소드에 제네릭 타입을 받을 수 있는 매개변수가 하나 있는 거
Concept
- 와일드카드 : <?> 형태로 사용. 모든 타입을 허용. 기본적으로 이미 타입이 결정된 제네릭 타입을 전달받아서 활용할 때 사용. 단일 메소드 내에서 알 수 없는 타입을 나타낼 때 사용
- 상한 와일드카드 : upper bound wild card.
<? extends T>와 같이 사용. T와 T를 상속받는 타입만 사용하게끔 제한. 주로 Collection 에서 데이터를 읽을 때(Produce) 사용 - 하한 와일드카드 : lower bound wild card.
<? super T>와 같이 사용. T와 T의 super 클래스 타입만 사용
wild card case
// 제약 없는 와일드카드. 모든 타입을 허용
public static void printList(List<?> list) { for (Object item : list) { System.out.print(item + " "); } System.out.println();}upper bounded card case
// input type으로 Number와 Number의 하위 클래스만 받는다.public static double sumList(List<? extends Number> list) { double sum = 0.0; for (Number num : list) { sum += num.doubleValue(); } return sum;}lower bounded wild card case
// Lower Bounded Wildcardpublic static void addIntegers(List<? super Integer> list) { list.add(1); list.add(2); list.add(3); }Type Erasure
Concept
- Type Erasure : 타입 소거. 제네릭 타입이 컴파일 시 제거되어 런타임에는 원시 타입으로 변환되는 것. 타입 소거는 제네릭이 없는 기존 코드와의 호환성을 유지하기 위해 도입되었다.
자바의 제네릭 타입은 컴파일 시점에만 존재하고 런타임에는 제네릭 정보가 지워지는 데 이를 Type Erasure라고 한다.
- 제네릭은 컴파일 타임에만 존재하고 런타임에는 해당 타입 정보가 지워지고 원시타입 으로 변환된다. #
- 따라서 생성자에서 제네릭 타입 매개 변수를 구체적인 타입으로 접근하거나 처리할 수 없다.
불가능한 예제
class TestClass<T> { public Myclass() { T instance = new T(); // Error
}}Variance
변성, 공변성, 반공변성, 무공변성
변성(Variance) 자체는 타입 시스템이 더 복잡해질 경우 서브타입 관계를 어떻게 가져갈 것인가에 대한 문제이다.
변성은 제네릭 타입의 서브타입 관계가 어떻게 되는지를 결정한다.
서브타입 관계의 실질적인 의미는 슈퍼타입(상위타입)의 객체를 서브타입으로 대체해도 동작에 문제가 없는지를 의미한다.(Liscov Substitution )
Concept
- 공변성 : Covariance. A가 B의 서브타입이라면,
C<A>는C<B>의 서브타입이다.서브타입의 관계가 유지되는 것. subtype 까지만 받는 경우. Wildcard의<? extends T>가 이에 해당한다 지정된 타입과 자식 타입만 허용하는 것. - 반공변성 : Contravariance. 서브타입의 관계가 역전되는 것. Supertype이나 동일한 타입을 받는 경우. Wildcard의
<? super T>가 이에 해당한다. 지정된 타입과 부모 타입만 허용하는것 - 무공변성 : Invariance. 서브타입 관계가 유지되지 않는 것. A가 B의 서브타입이라도
C<A>와C<B>는 서로 관련이 없다. 기본적으로 타입 변환이 안된다. 일반적인 제네릭 타입은 무공변성을 가진다. - Bivariance : Covariance하면서 Contravariance를 모두 포함하는 경우.
PECS
Producer Extends Consumer Super.
producer case
extends 키워드를 사용해 타입의 상한을 제한할 경우 컬렉션은 데이터를 제공하는 Producer의 역할을 한다. 이 컬렉션에서 데이터를 꺼내는 것은 안전하지만, 데이터를 삽입하는 것은 안전하지 않을 수 있다.
List<? extends Number> numbers = new ArrayList<Integer>();Number n = numbers.get(0); // 데이터를 가져오는 것은 허용numbers.add(new Integer(10)); // Error, 데이터를 추가하는 것은 불가능consumer case
super 키워드를 사용해 타입의 하한을 제한할 경우 컬렉션은 데이터를 소비하는 Consumer 의 역할을 한다. 이 컬렉션에 데이터를 안전하게 삽입할 수 있지만, 꺼내는 것은 안전하지 않을 수 있다.
List<? super Integer> integers = new ArrayList<Number>();integers.add(new Integer(10)); // consume dataInteger n = integers.get(0); // Error, 데이터를 가져오는 것은 불가능Concept
- PECS : Producer Extends Consumer Super. extends 를 사용하는 경우 자바 Collection을 producer로 사용하고 super를 사용하는 경우 Collection을 Consumer로 사용.
[[java-mid2-index]]