2010-03-23 4 views

답변

119

공분산 : 그것은 슈퍼 # getSomething의 리턴 타입의 서브 클래스 반환하기 때문에

class Super { 
    Object getSomething(){} 
} 
class Sub extends Super { 
    String getSomething() {} 
} 

하위 번호의 getSomething는 공변입니다 (을하지만 Super.getSomething의 계약을 fullfills())

Contravariance

class Super{ 
    void doSomething(String parameter) 
} 
class Sub extends Super{ 
    void doSomething(Object parameter) 
} 

하위 #의 해봐요은 contrava입니다 (슈퍼 # doSomething의 계약을 완전히 채운다.)

Notice :이 예제는 자바에서는 작동하지 않는다. Java 컴파일러는 오버로드하여 doSomething() - 메소드를 재정의하지 않습니다. 다른 언어는 이러한 형태의 반공 변성을지지합니다.

제네릭

이 제네릭에 대한 수도 있습니다 : 당신은 이제 뭔가 가되어야하므로 (일반 매개 변수를 사용하지 않는 covariantList의 모든 메소드에 액세스 할 수 있습니다

List<String> aList... 
List<? extends Object> covariantList = aList; 
List<? super String> contravariantList = aList; 

"extends Object"), getter는 정상적으로 작동합니다 (반환 된 객체는 항상 "Object"유형이므로)

contravariantList의 경우와 반대입니다. 일반 매개 변수를 사용하여 모든 메서드에 액세스 할 수 있습니다.이 메서드는 "String"의 수퍼 클래스 여야하므로 항상 하나만 전달할 수 있지만 getter는 사용할 수 없습니다 (반환 된 형식은 다른 수퍼 유형 일 수 있습니다 문자열의)

+68

자바에서는 contravariance의 첫 번째 예제가 작동하지 않습니다. Sub 클래스의 doSomething()은 오버로드가 아니라 오버라이드입니다. –

+13

실제로. Java는 부속 유형에서 반올림 인수를 지원하지 않습니다. 관심 대상 메서드가 유형을 반환하기위한 공분산 만 (첫 번째 예와 같이). –

+0

좋은 답변입니다. 공분산은 나에게 논리적으로 보입니다. 하지만 당신은 contravariance를 설명하는 JLS에서 단락을 가르쳐 주시겠습니까? 왜 Sub.do가 필요합니까? – Mikhail

1

Liskov substitution principle을보세요. 실제로 클래스 B가 클래스 A를 확장하면 A가 필요할 때마다 B를 사용할 수 있어야합니다.

+2

이와 질문에 대답하지 않고 오해의 소지가 있습니다. 의미 적 정확성을 깨뜨리고 따라서 LSP를 위반하는 변형 시스템을 설계하는 것이 전적으로 가능할 것입니다. –

+0

'contra variant'의 경우에는 그렇지 않습니다. 'super.doSomething ("String")'은'sub.doSomething (Object)'로 바꿀 수 없습니다. – zinking

38

공분산 : 반복 및 반복기. 거의 항상 공동 변종 Iterable 또는 Iterator을 정의하는 것이 좋습니다. Iterator<? extends T>Iterator<T>처럼 사용할 수 있습니다. 형식 매개 변수가 나타나는 유일한 곳은 next 메서드의 반환 형식이므로 T으로 안전하게 업스트림 할 수 있습니다. 그러나 S의 범위가 T 인 경우 변수에 Iterator<S>을 할당 할 수도 있습니다. 예를 들어, 당신은 찾기 메소드 정의하는 경우 :

boolean find(Iterable<Object> where, Object what) 

당신이 List<Integer>5으로 호출 할 수 없습니다를, 그래서 더 나은

boolean find(Iterable<?> where, Object what) 

콘트라 - 분산으로 정의되어 : 비교기.Comparator<? super T>은 거의 항상 Comparator<T>으로 사용할 수 있기 때문에 사용하는 것이 좋습니다. type 매개 변수는 compare 메서드 매개 변수 유형으로 만 표시되므로 T을 안전하게 전달할 수 있습니다.예를 들어 당신이 DateComparator implements Comparator<java.util.Date> { ... }이 있고 그 비교기와 List<java.sql.Date> 정렬 할 경우 (java.sql.Datejava.util.Date의 하위 클래스), 당신이 함께 할 수있는 :

<T> void sort(List<T> what, Comparator<? super T> how) 

하지만

<T> void sort(List<T> what, Comparator<T> how)