작업 중 문제가 발생했습니다. 코드에 다음과 같이 설명되어 있습니다.
package test;import java.util.LinkedList; import java.util.List;public class ListTest { public void func(List<Base> list) { } public static void main(String args[]) { ListTest lt = new ListTest(); List<Derived> list = new LinkedList<Derived>(); lt.func(list); // 编译报错 } }class Base { }class Derived extends Base { }
여기서 Base 목록을 매개변수로 사용할 수 있는 func 함수를 작성해야 합니다. Derived는 Base의 파생 클래스이므로 Derived의 목록도 Base의 목록의 파생 클래스여야 하기 때문에 Derived 목록을 전달해도 괜찮을 것이라고 생각했는데 컴파일러에서 오류를 보고했습니다.
이유는 인터넷에서 몇 가지 정보를 확인했기 때문입니다. Java의 제네릭은 공변적이지 않습니다.
제네릭의 공변성과 반공변성은 둘 다 용어입니다. 전자는 원래 지정된 파생 유형보다 덜 파생된(덜 구체적인) 유형을 사용하는 능력을 나타내고 후자는 원래 지정된 유형보다 덜 파생된 유형입니다. 파생 유형은 더 파생된(더 구체적인) 유형입니다.
예를 들어 C#의 제네릭은 공분산을 지원합니다.
IEnumerable<Derived> d = new List<Derived>(); IEnumerable<Base> b = d;
그러나 Java의 제네릭은 공분산을 지원하지 않습니다. 위와 유사한 코드는 Java에서 컴파일할 수 없습니다.
그러나 흥미로운 점은 Java의 배열이 공분산을 지원한다는 것입니다. 예를 들면 다음과 같습니다.
Integer[] intArray = new Integer[10]; Number[] numberArray = intArray;
요약: Java의 제네릭은 유형 안전 관점에서 공분산을 지원하지 않습니다. 예를 들어 C#에서는 이 디자인을 사용하지 않습니다. Java 설계자는 사용 편의성과 유형 안전성 중에서 선택했다고 말할 수 있습니다.
마지막으로 원래 질문으로 돌아가서 func 메소드를 구현하려면
public void func(List list) { }
으로 수정하거나 매개변수화된 유형을 사용할 수 있습니다.
public <T> void func(List<T> list) { }
하지만 이것도 문제가 있습니다. func의 매개변수 유형이 흐릿해집니다. 더 좋은 방법은 func를 변경하는 것이 아니라 매개변수를 전달할 때 기본 유형 목록을 전달하는 것입니다. 이를 위해서는 요소를 목록에 추가할 때 요소를 기본 유형으로 변환해야 합니다.
PS: 매개변수 유형 제한:
public void func(List<? extends Base> list) { }