2011-06-11 4 views
3

오늘 흥미로운 문제가 발생했습니다. 다음 코드를 고려하십시오.제네릭 세트를 캐스팅 할 수 없습니까?

public static class Parent {} 
public static class Child extends Parent {} 

Set<Child> childs = new HashSet(); 
Set<Parent> parents = (Set<Parent>)childs; //Error: inconvertible types 

Parent parent = (Parent)new Child(); //works?! 

왜 그와 같은 캐스트가 좋지 않습니까? 암시 적 캐스트는 제네릭의 다양한 규칙으로 인해 작동하지 않을 것이라고 기대하지만 명시 적 캐스트는 왜 작동하지 않을까요?

+0

당신이'HashSet의 을 말한다면'이 될 수 있습니다. –

+0

@ahmet say'HashSet '_where? _ –

답변

16

Java generics are not covariant 때문에 전송되지 않습니다.

List<Child> children = new ArrayList(); 
List<Parent> parents = (List<Parent>)children; 

다음이 경우에 어떤 일이 일어날 것입니다 : 컴파일러이 허용하는 경우

?

parents.add(new Parent()); 
Child c = children.get(0); 

마지막 줄은 Child —하지만 ParentParent를 할당하려고 시도 할 것은 Child하지 않습니다!

모든 Child은 (Child extends Parent부터) Parent하지만 모든 ParentChild을하지 않습니다.

+0

재미있는 점입니다. 하지만 내 API 비록 혼란을 일으키는. 답변 주셔서 감사합니다 – TheLQ

+0

괜찮습니다. 그것이 나쁘다면 API를 매개 변수화하는 올바른 방법을 이해하지 못한다면 몇 가지 구체적인 예를 들어 다른 질문을하고 보겠습니다. –

1

Set<Parent>에는 Parent의 하위 클래스가 포함될 수 있습니다. Set<Child>에는 Child의 하위 클래스가 포함될 수 있습니다. 따라서 Child의 하위 클래스가 아닌 Parent의 하위 클래스는 하나에는 허용되지만 다른 하나는 허용되지 않으므로 호환되지 않는 유형이됩니다.

1

하위 집합 (sic)이 상위 집합이 아니기 때문에. 제네릭 (매개 변수화 된) 세트를 정의하는 것은 새로운 클래스를 정의하는 것과 실질적으로 동일하므로 두 개의 분리 된 클래스를 정의합니다.

1

비록, 제네릭의 슈퍼 유형은 약간 다르게 작동 :

Set<Child> childs = new HashSet(); 
Set<? extends Parent> parents = childs; 

세트는 세트의 슈퍼 타입과 설정

난 당신이 일반적인 사이에 상속이 없다는 것을 이해하는 this docs about generics을 읽어 보는 것이 좋습니다 컨테이너가 상속이 아니기 때문에. 상속은 무엇보다도 전문화를 의미합니다. 동물을 잡을 수있는 상자를 생각해 봅시다. 호랑이 만 들어있는 상자에서 파생 될 수 있습니다. 그렇지만 상자가 호랑이를 위해 할 수 있다는 것을 의미 할 것입니다.하지만 수퍼 유형이 할 수있는 모든 것을 할 수 있습니다. 모든 동물을위한 상자. 인간이 두 가지 유형의 택 소노 미 (hyperonimic hierarchy) (전문화, 상속)와 명목상의 계층 구조 (컨테이너/포함)에 대해 생각하는 것은 매우 지저분합니다. 마지막 줄에

는, 필요도 캐스팅 없습니다 :

Parent parent = new Child(); 

스테판

관련 문제