Java에서 오버로딩 및 오버라이드의 경우 공분산 및 반공 분산을 보여주는 함수의 예를 제공합니까? [닫은]


답변:


155

공분산 :

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

Sub # getSomething은 Super # getSomething 반환 유형의 하위 클래스를 반환하기 때문에 공변 적입니다 (그러나 Super.getSomething ()의 계약을 완전히 채 웁니다).

반 변성

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

Sub # doSomething은 Super # doSomething 매개 변수의 수퍼 클래스 매개 변수를 취하기 때문에 반 변성입니다 (하지만 Super # doSomething의 계약을 완전히 채 웁니다).

주의 :이 예제는 Java에서 작동하지 않습니다. Java 컴파일러는 doSomething ()-Method를 오버로드하고 재정의하지 않습니다. 다른 언어는이 스타일의 반 변성을 지원합니다.

제네릭

Generics에서도 가능합니다.

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

이제 covariantList일반 매개 변수를 사용하지 않는 모든 메소드에 액세스 할 수 있지만 ( "extends Object" 여야 하므로) getter는 제대로 작동합니다 (반환 된 객체는 항상 "Object"유형이 됨).

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


79
반공 변성의 첫 번째 예는 Java에서 작동하지 않습니다. Sub 클래스의 doSomething ()은 오버로드가 아니라 오버로드입니다.
Craig P. Motlin 2011

15
과연. Java는 하위 유형 지정에서 반 변성 인수를 지원하지 않습니다. 메서드 반환 유형에 대한 공분산 만 해당됩니다 (첫 번째 예에서와 같이).
the_dark_destructor 2012

좋은 대답입니다. 공분산은 나에게 논리적으로 보입니다. 하지만 JLS에서 반 변성을 설명하는 단락을 지적 해 주시겠습니까? Sub.doSomething이 호출되는 이유는 무엇입니까?
Mikhail

2
Craig가 지적했듯이 그렇지 않습니다. 나는 여기에 재정의와 과부하 사이의 충돌이 있다고 생각하며 SUN은 (항상 그렇듯이) 이전 버전과 호환되는 옵션을 선택했습니다. 따라서 Java에서는 메서드를 재정의 할 때 반 변성 매개 변수를 사용할 수 없습니다.
2013

1
내 대답에 대해 왜 내가 반대표를 받는지 아는 것이 좋습니다.
하드 코딩 됨

48

공분산 : Iterable 및 Iterator. 공변량 Iterable또는 Iterator. Iterator<? extends T>단지로 사용할 수 있습니다 Iterator<T>유형 매개 변수가 나타납니다가의 리턴 타입 유일한 장소 - next이 안전하게 최대 캐스트 할 수 있도록, 방법 T. 그러나 Sextends 가있는 경우 유형의 변수에 T할당 할 수도 있습니다 . 예를 들어 find 메소드를 정의하는 경우 :Iterator<S>Iterator<? extends T>

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

List<Integer>및 로 호출 할 수 5없으므로 다음과 같이 더 잘 정의됩니다.

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

Contra-variance : Comparator. 거의 항상 사용하는 것이 합리적입니다.. 그대로 사용할 Comparator<? super T>수 있기 때문 Comparator<T>입니다. 유형 매개 변수는 compare메소드 매개 변수 유형 으로 만 표시 되므로 T안전하게 전달할 수 있습니다. 예를 들어 DateComparator implements Comparator<java.util.Date> { ... }a가 List<java.sql.Date>있고 해당 비교기 로 정렬하려는 경우 (은의 java.sql.Date하위 클래스 임 java.util.Date) 다음과 같이 할 수 있습니다.

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

하지만

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

-4

상기 봐 Liskov 대체 원칙 . 실제로 B 클래스가 A 클래스를 확장하면 A가 필요할 때마다 B를 사용할 수 있어야합니다.


6
이것은 질문에 대한 답이 아니며 오해의 소지가 있습니다. 의미 적 정확성을 깨고 LSP를 위반하는 변형 시스템을 설계하는 것이 전적으로 가능할 것입니다.
Matt Whipple

이것은 contra variant말할 경우가 아닙니다 . super.doSomething("String")로 대체 할 수 없습니다 sub.doSomething(Object).
zinking

그것은 문제되지 않습니다
OlivierTerrien
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.