Java | 제네릭과 자바 타입 시스템의 변성

Lumpen·2025년 5월 1일
0

Java

목록 보기
33/38

변성

타입 시스템에서의 변성이란 타입이 변하는 성질을 띄는지에 대한 것으로
불변성, 공변성, 반공변성으로 표현한다

불변성

전달된 타입이 변하지 않는다
타입 불변성을 띄면 읽기와 쓰기 모두
타입을 안전하게 사용할 수 있다

공변성

설정한 타입이 타입 상한이 된다
상속 관계에서 구체적인 타입인 서브 타입을 일반적인 타입인 수퍼 타입에서도
안전하게 취급할 수 있는 경우
수퍼 타입을 사용하는 곳에서 서브 타입도 지원하는 것

공변성을 지원하는 경우
타입 매개변수 제한으로 설정한 타입과 하위 타입을 모두 받을 수 있고
설정 타입보다 하위 타입이 입력되더라도 상위 타입으로 다룬다
읽기 작업 시 타입을 안전하게 사용할 수 있다

<? extends Integer> 공변성은 해당 리스트가 Integer 를 생산할 수 있는 능력을 보장한다는 타입 경계를 설정하는 것으로 볼 수 있다
리스트에서 꺼낸 요소는 최소한 Integer 타입임을 보장한다

List<? extends Number>List<Integer>, List<Double>Number의 하위 타입 리스트를 참조할 수 있다
이는 자바의 객체 지향적 특성인 다형성 덕분이다
하위 타입의 객체는 상위 타입으로 참조될 수 있기 때문

  • 읽기 시: 컴파일러는 리스트의 요소가 최소한 Number 타입임을 보장하므로, Number 타입으로 안전하게 참조할 수 있다
  • 쓰기 시: 쓰기 작업은 정확한 타입을 보장할 수 없기 때문에 안전하지 않다

반공변성

설정한 타입이 타입 하한이 된다
상속 관계에서 수퍼 타입을 서브 타입에서도 안전하게 취급할 수 있는 경우
서브 타입을 사용하는 곳에서 수퍼 타입도 지원하는 것

반공변성을 지원하는 경우
제한으로 설정한 타입과 설정한 타입의 상위 타입을 모두 받을 수 있고
설정 타입보다 상위 타입으로 입력되더라도 설정 타입으로 다룬다
쓰기 작업 시 안전하게 추가할 수 있다

<? super Integer> 반공변성은 해당 리스트가 Integer 를 소비(사용)할 수 있는 능력을 보장한다는 타입 경계를 설정하는 것으로 볼 수 있다

List<? super Integer>Integer 또는 Integer의 상위 타입(Number, Object)을 담을 수 있는 리스트가 된다
리스트의 실제 타입은 Integer보다 더 일반적인 타입일 수 있지만
Integer를 처리하는 데는 문제가 없다는 것을 컴파일러에게 알려주는 것

  • 쓰기 시: Integer 객체는 Integer, Number, Object 어떤 타입의 리스트에도 안전하게 추가될 수 있다
    이는 Integer가 이 모든 타입의 하위 타입이기 때문
    컴파일러는 최소한 Integer 객체를 추가하는 것이 안전함을 보장한다
  • 읽기 시: 리스트에서 꺼낸 요소는 어떤 상위 타입일지 모르기 때문에, 구체적인 타입으로 안전하게 다루려면 명시적인 타입 검사 후 캐스팅이 필요하며, 가장 안전한 타입은 Object 가 된다

제네릭의 불변성

제네릭은 타입 상한을 지정할 수 있지만
들어온 타입 그대로를 반환한다

	public static <T extends Object> T genericMethod(T generic) {
    	return generic
    }

위와 같은 제네릭 메서드의 제네릭 타입 T 가 있을 때

	Integer result = GenericPractice.genericMethod(10);

Integer 타입을 인수로 전달하면
반환값 역시 Integer 가 된다

<T extends Object> 로 타입의 상한을 설정할 수는 있지만
입력된 타입이 변하지 않는다

와일드카드의 변성

와일드카드는 공변성과 반공변성을 지원한다

공변성

List<? extends Integer>

반공변성

List<? super Integer>

profile
떠돌이 생활을 하는. 실업자, 부랑 생활을 하는

0개의 댓글