Cho ví dụ về các hàm chứng minh hiệp phương sai và phương sai trong các trường hợp nạp chồng và ghi đè trong Java? [đóng cửa]


105

Vui lòng chỉ ra một ví dụ điển hình cho hiệp phương sai và phương sai trong Java.

Câu trả lời:


155

Phương sai:

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

Sub # getSomething là hiệp biến vì nó trả về một lớp con của kiểu trả về Super # getSomething (nhưng điền đầy đủ hợp đồng của Super.getSomething ())

Sự tương phản

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

Sub # doSomething là trái ngược vì nó nhận tham số của một lớp cha của tham số Super # doSomething (nhưng, một lần nữa, điền đầy đủ hợp đồng của Super # doSomething)

Lưu ý: ví dụ này không hoạt động trong Java. Trình biên dịch Java sẽ quá tải và không ghi đè phương thức doSomething () -. Các ngôn ngữ khác cũng hỗ trợ phong cách đối lập này.

Generics

Điều này cũng có thể cho Generics:

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

Bây giờ bạn có thể truy cập vào tất cả các phương thức covariantListkhông có tham số chung (vì nó phải là một thứ gì đó "Extended Object"), nhưng getters sẽ hoạt động tốt (vì đối tượng trả về sẽ luôn có kiểu "Object")

Điều ngược lại là đúng đối với contravariantList: Bạn có thể truy cập tất cả các phương thức có tham số chung (bạn biết nó phải là lớp cha của "String", vì vậy bạn luôn có thể chuyển một), nhưng không có getters (Kiểu trả về có thể thuộc bất kỳ siêu kiểu nào khác của String )


79
Ví dụ đầu tiên về sự tương phản không hoạt động trong Java. doSomething () trong lớp Sub là quá tải, không phải là ghi đè.
Craig P. Motlin

15
Thật. Java không hỗ trợ các đối số trái ngược trong kiểu con. Chỉ hiệp phương sai cho các kiểu trả về của phương thức quan tâm (như trong ví dụ đầu tiên).
the_dark_destructor

Câu trả lời chính xác. Đối với tôi, hiệp phương sai có vẻ hợp lý. Nhưng bạn có thể chỉ cho tôi một đoạn trong JLS mô tả sự trái ngược không? Tại sao Sub.doSomething được gọi?
Mikhail

2
Như Craig đã chỉ ra, không phải vậy. Tôi nghĩ rằng đây là một cuộc xung đột giữa ghi đè và quá tải và SUN đã chọn (như mọi khi) tùy chọn tương thích ngược. Vì vậy, trong Java, bạn không thể sử dụng các tham số tương phản khi ghi đè một phương thức.
hardcoded

1
Rất vui khi biết lý do tại sao tôi nhận được phiếu phản đối cho câu trả lời của mình.
Hardcoded

48

Đồng phương sai: Có thể lặp lại và Trình lặp lại. Hầu như luôn luôn có ý nghĩa khi xác định một biến thể đồng Iterablehoặc Iterator. Iterator<? extends T>có thể được sử dụng giống như Iterator<T>- nơi duy nhất mà tham số kiểu xuất hiện là kiểu trả về từ nextphương thức, vì vậy nó có thể được truyền lên một cách an toàn T. Nhưng nếu bạn đã Smở rộng T, bạn cũng có thể gán Iterator<S>cho một biến kiểu Iterator<? extends T>. Ví dụ: nếu bạn đang xác định một phương pháp tìm:

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

bạn sẽ không thể gọi nó bằng List<Integer>5, vì vậy nó được định nghĩa tốt hơn là

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

Tương phản phương sai: Bộ so sánh. Nó hầu như luôn luôn có ý nghĩa khi sử dụng Comparator<? super T>, bởi vì nó có thể được sử dụng giống như vậy Comparator<T>. Tham số kiểu chỉ xuất hiện dưới comparedạng kiểu tham số phương thức, vì vậy Tcó thể được truyền an toàn cho nó. Ví dụ: nếu bạn có một DateComparator implements Comparator<java.util.Date> { ... }và bạn muốn sắp xếp một List<java.sql.Date>với bộ so sánh đó ( java.sql.Datelà một lớp con của java.util.Date), bạn có thể thực hiện với:

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

nhưng không phải với

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

-4

Nhìn vào nguyên tắc thay thế Liskov . Trên thực tế, nếu lớp B mở rộng lớp A thì bạn có thể sử dụng B bất cứ khi nào yêu cầu A.


6
Điều này không trả lời câu hỏi và gây hiểu lầm. Hoàn toàn có khả năng thiết kế một hệ thống biến thể phá vỡ tính đúng đắn về ngữ nghĩa và do đó vi phạm LSP.
Matt Whipple

đây không phải là trường hợp để contra variantnói. super.doSomething("String")không thể thay thế bằng sub.doSomething(Object).
zinking

Nó không phải là câu hỏi
OlivierTerrien
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.