2010-06-08 38 views
14

Có duy trì khả năng tương thích ngược với các phiên bản cũ hơn (chưa được phổ biến) của Collection không? Hoặc là có một chi tiết tinh tế hơn mà tôi đang thiếu? Tôi thấy mẫu này lặp lại trong remove cũng (remove(Object o)), nhưng add được tổng quát thành add(E e).Tại sao chúng ta có chứa (Object o) thay vì chứa (E e)?

+2

bản sao có thể có của [Tại sao Bộ sưu tập Java không loại bỏ các phương pháp chung?] (Http://stackoverflow.com/questions/104799/why-arent-java-collections-remove-methods-generic) – newacct

Trả lời

10

mất Object vì đối tượng khớp với không phải là cùng loại với đối tượng mà bạn chuyển vào ; nó chỉ yêu cầu chúng bằng nhau. Từ đặc tả của , contains(o) trả về true nếu có một đối tượng e sao cho (o==null ? e==null : o.equals(e)) là đúng.Lưu ý rằng không có gì yêu cầu oe để cùng loại. Điều này theo sau thực tế là phương thức equals() lấy một tham số Object, không chỉ cùng loại với đối tượng.

Mặc dù thông thường có nhiều lớp có số equals() được xác định sao cho đối tượng của nó chỉ có thể bằng với các đối tượng thuộc lớp riêng của nó, đó chắc chắn không phải lúc nào cũng vậy. Ví dụ, đặc điểm kỹ thuật cho List.equals() nói rằng hai đối tượng List là bằng nhau nếu cả hai đều là List và có cùng nội dung, ngay cả khi chúng là các triển khai Danh sách khác nhau. Vì vậy, quay trở lại ví dụ trong câu hỏi này, có thể có một Collection<ArrayList> và để tôi gọi với một đối số LinkedList và có thể trả về true nếu có danh sách có cùng nội dung. Điều này sẽ không thể nếu là chung và hạn chế loại đối số của nó là E.

Trong thực tế, thực tế là mất bất kỳ đối tượng như một tham số cho phép việc sử dụng thú vị mà bạn có thể sử dụng nó để kiểm tra sự tồn tại của một đối tượng trong bộ sưu tập thỏa mãn một tài sản nhất định:

Collection<Integer> integers; 
boolean oddNumberExists = integers.contains(new Object() { 
    public boolean equals(Object e) { 
     Integer i = (Integer)e; 
     if (i % 2 != 0) return true; 
     else return false; 
    } 
}); 
+3

Ngoài ra phương thức này có chữ ký 'contains (Object o)' cung cấp một khẩu súng thực sự tốt đẹp để thuận tiện bắn mình trong một chân. Phương pháp này thực sự là một giới thiệu về giới hạn của Java Generics. –

4

Đó là bởi vì các contains chức năng sử dụng các equals chức năng, và các chức năng equals được định nghĩa trong lớp cơ sở Object với một chữ ký của equals(Object o) hơn equals(E e) (vì không phải tất cả các lớp học mang tính tổng quát). Trường hợp tương tự với chức năng remove - nó truyền tải bộ sưu tập bằng cách sử dụng hàm equals có đối số Đối tượng.

Điều này không trực tiếp giải thích quyết định, vì họ vẫn có thể sử dụng loại E và cho phép nó tự động truyền để nhập Object khi gọi tới equals; nhưng tôi tưởng tượng họ muốn cho phép hàm được gọi trên các kiểu Object khác. Không có gì sai khi có một số Collection<Foo> c; và sau đó gọi số c.contains(somethingOfTypeBar) - nó sẽ luôn trả về sai, và vì vậy nó giúp loại bỏ sự cần thiết phải nhập Foo (có thể ném ngoại lệ) hoặc để bảo vệ ngoại lệ, gọi typeof. Vì vậy, bạn có thể tưởng tượng nếu bạn đang lặp qua một cái gì đó với các loại hỗn hợp và gọi contains trên mỗi phần tử, bạn có thể chỉ cần sử dụng chức năng chứa trên tất cả chúng thay vì cần bảo vệ.

Nó thực sự gợi nhớ của các ngôn ngữ lỏng lẻo, đánh máy "mới hơn", khi bạn nhìn vào nó như vậy ...

+0

Điều này không có gì để làm với lý do thực sự. Sẽ tốt hơn nếu có một số mức kiểm tra kiểu trên 'contains' và có thể' remove'. Nó sẽ dễ bị lỗi hơn nhiều. –

+3

"nó sẽ luôn luôn trả về false" không có nó sẽ không. nó là hoàn toàn có thể cho một lớp để .equals một đối tượng của một lớp học – newacct

5

trả lời ở đây.
Why aren't Java Collections remove methods generic?
Tóm lại, họ muốn tối đa hóa khả năng tương thích ngược, bởi vì các bộ sưu tập đã được giới thiệu từ lâu trước khi dùng thuốc generic.

Và để thêm từ tôi: video mà anh ấy giới thiệu đáng xem.
http://www.youtube.com/watch?v=wDN_EYUvUq0

cập nhật
Để làm rõ, người đàn ông nói rằng (trong video) là một trong những người được cập nhật bản đồ java và các bộ sưu tập để sử dụng Generics. Nếu anh ta không biết, thì ai.

0

Vì nếu không nó chỉ có thể được so sánh với đối sánh chính xác của loại thông số, các bộ sưu tập ký tự đại diện cụ thể sẽ ngừng hoạt động, ví dụ:

class Base 
{ 
} 

class Derived 
    extends Base 
{ 
} 

Collection< ? extends Base > c = ...; 

Derived d = ...; 

Base base_ref = d; 

c.contains(d); // Would have produced compile error 

c.contains(base_ref); // Would have produced compile error 

EDIT
Đối với những người nghi ngờ người nghĩ đó không phải là một trong những lý do này, đây là một danh sách mảng sửa đổi với một sẽ được generified chứa phương pháp

class MyCollection<E> extends ArrayList<E> 
{ 
    public boolean myContains(E e) 
    { 
     return false; 
    } 
} 

MyCollecttion< ? extends Base > c2 = ...; 

c2.myContains(d); // does not compile 
c2.myContains(base_ref); // does not compile 

Về cơ bản contains(Object o) là một hack để làm trường hợp sử dụng rất phổ biến này để làm việc với Java Generics.

+0

Chăm sóc để giải thích downvote? –

+0

Trong kịch bản bình thường, không ai muốn bỏ một bộ sưu tập vào 'Bộ sưu tập 'trong thao tác phần tử. Nếu trường hợp này xảy ra, phương thức 'add (E e)' cũng sẽ bị lỗi. – Jai

+0

@Jai. Đây là một kịch bản 'void myMethod (Collection coll)'. Nếu bên trong bạn cần phải xem một số verison của 'Foo' được chứa trong colleciton này, bạn sẽ đạt đến giới hạn được mô tả trong câu trả lời này. –

0

"Cái giỏ táo đó có chứa màu cam này không?"

không thể cung cấp câu trả lời TRUE rõ ràng. nhưng vẫn còn quá khả năng:

  1. câu trả lời là FALSE.
  2. câu hỏi không được định dạng tốt, không được chuyển biên dịch.

api bộ sưu tập đã chọn người đầu tiên. nhưng lựa chọn thứ 2 cũng sẽ có ý nghĩa hoàn hảo. một câu hỏi như thế là một câu hỏi nhảm nhí 99,99% số lần, vì vậy đừng hỏi!

+0

Câu hỏi không nên được coi là không đúng định dạng, nếu có, ví dụ: có hai giỏ đựng trái cây, và muốn biết nếu có trái cây trong một giỏ phù hợp với trái cây trong trái khác. Nếu người ta biết rằng một rổ chỉ chứa táo và một quả chỉ chứa cam, nó có thể có ý nghĩa để đoản mạch tìm kiếm một trận đấu, nhưng giả sử một rổ được biết là chỉ chứa táo và quả kia chứa trái cây hỗn hợp. Hỏi giỏ táo về mỗi loại trái cây trong giỏ khác mà không xác thực loại của nó trước sẽ dễ dàng hơn việc kiểm tra từng loại trái cây trước khi hỏi xem đó có phải là quả táo hay không. – supercat

+0

trong ví dụ của tôi, tham số được biết là màu da cam, do đó câu hỏi có vẻ vô lý. trong ví dụ của bạn, câu hỏi sẽ là "giỏ táo đó có chứa trái cây này không?", đó là hợp pháp.trường hợp sử dụng là hiếm hơn mặc dù. Chúng tôi có thể thiết kế lại API để cho phép câu hỏi của bạn trong khi cấm câu hỏi của tôi, bằng cách hạn chế loại tham số là loại siêu của Apple. – irreputable

+0

Không có cơ chế trong. Net thông qua đó một phương pháp có thể hạn chế một tham số, chung chung hay cách khác, trở thành siêu kiểu của một số kiểu khác, và tôi không nghĩ Java cũng có cơ chế như vậy. Một thứ như vậy sẽ có khuynh hướng vi phạm Nguyên tắc Thay thế Liskov, vì một phương pháp có thể sử dụng được với 'Trái cây' nên có thể sử dụng được với 'Màu da cam'. Có nhiều cách trong .Net qua đó người ta có thể sử dụng các thẻ 'Lỗi thời 'để kích hoạt các trình dịch squawks trong một số trường hợp ngớ ngẩn có thể nhận dạng tĩnh, nhưng tôi nghĩ rằng sẽ khó hiểu hơn là hữu ích. – supercat

Các vấn đề liên quan