2012-07-18 45 views
7

Được rồi, vì vậy Java không cho phép như sau:Generics và ký tự đại diện: Java thích "mới Foo <Bar<?>>"

Foo<?> hello = new Foo<?>(); 

Điều này làm cho sense-- sau khi tất cả, điểm của generics nếu bạn là gì chỉ cần hộp/unbox tất cả mọi thứ anyways?

Có gì lạ, là Java không cho phép điều này:

Foo<Bar<?>> howdy = new Foo<Bar<?>>(); 

Cấp, điều này thực sự hoàn thành hơn, mặc dù tại một số điểm, sẽ có một dàn diễn viên để có được bất cứ điều gì Bar đang làm việc với. Nhưng nếu Java là okay với một số đặc hiệu, tại sao nó không cho phép điều này ?:

Foo<? extends Mal> bonjour = new Foo<? extends Mal>(); 

Lý do duy nhất tôi hỏi là tôi đang sửa chữa phải dựa vào các "ký tự đại diện trong một tham số lớp của một nhà xây dựng ", và nghiêm túc muốn biết ý nghĩa/ý định đằng sau nó.

EDIT: Để làm rõ câu hỏi của tôi, những điều khoản này được cho phép/không cho phép? Tôi biết rằng "Java không cho phép ký tự đại diện trong các nhà xây dựng", nhưng câu hỏi là, lý do tại sao tất cả sự kỳ quặc này? Tại sao các ký tự đại diện bị chặn không được phép nếu các ký tự đại diện lồng nhau được không?

Trả lời

5

Đối với lý do cơ bản: new Foo<?> có lẽ tốt hơn nên được viết là new Foo<Object>, do đó giới hạn trình biên dịch ở đây buộc phải viết mã có thể đọc được như bạn có thể. Ví dụ cuối cùng cũng có thể là new Foo<Mak>(), vì bạn không thể làm gì trên số Foo<? extends Mal> mà bạn không thể thực hiện trên Foo<Mal>.Lưu ý rằng trò chuyện không đúng: một số Foo<Mal> có thể chấp nhận các đối số Mal trong đó Foo<? extends Mal> thì không.

Mặt khác, bạn thực sự có thể muốn một đối tượng Foo có thể xử lý Bar đối tượng thuộc bất kỳ loại nào, do đó, Foo<Bar<?>> có ý nghĩa hoàn hảo. Đây sẽ là trường hợp nếu bạn chỉ truy cập các phương thức Bar mà không dựa vào đối số kiểu. Không có gì để trình biên dịch phàn nàn ở đây.

+0

Tôi nghĩ rằng tôi hiểu những gì bạn đang nói: nếu một nhà xây dựng chấp nhận một tham số lớp 'Mal', cá thể vốn đã chấp nhận bất kỳ thứ gì là lớp con của' Mal' (mặc dù _reference_ đối với cá thể sẽ không thể trỏ đến chung với một phân lớp trừ khi một ký tự đại diện được chỉ định.) – Philip

+0

Nhìn nhận xét của tôi hơn một năm sau ... Tôi khá chắc chắn đó là một trong những điều khó hiểu nhất mà tôi từng nói. – Philip

1

Khi bạn instanciate một thể hiện của một loại tham số, bạn phải chỉ định một loại. ?? extends Mal không phải là loại. Bar<?> là một loại. Bạn có thể tìm thêm thông tin về số này page.

Dưới đây là một ví dụ cho trường hợp thứ hai của bạn:

Bar<Object> bar1 = ...; 
Bar<String> bar2 = ...; 
List<Bar<?>> list = new ArrayList<Bar<?>>(); 
list.add(bar1); 
list.add(bar2); 

Bạn có thể tưởng tượng để lưu trữ các trường hợp Bar trong một danh sách, nhưng bạn không cần phải biết các tham số kiểu của họ.

3

Lý do khai báo đầu tiên và thứ ba của bạn không làm việc là vì JLS §15.9:

Đó là một lỗi thời gian biên dịch nếu bất kỳ đối số loại được sử dụng trong một biểu thức tạo dụ lớp là loại ký tự đại diện đối số (§4.5.1).

Trong tuyên bố đầu tiên của bạn, ? là loại ký tự đại diện. Trong tờ khai thứ ba của bạn, ? extends Mal là loại ký tự đại diện.

Lý do khai báo thứ hai của bạn không hoạt động là vì Bar<?> không phải là loại ký tự đại diện. Loại của Bar<?>Bar.

Bạn có ý nghĩa gì với "ký tự đại diện bên trong tham số lớp của một hàm tạo"?

+0

Vâng vâng, chúng là các ký tự đại diện và ký tự đại diện không được phép trong những trường hợp đó-- nhưng câu hỏi của tôi là _why_? Tại sao quyết định thiết kế này lại được thực hiện? Tại sao khối mã thứ ba kém hợp pháp hơn thứ hai? – Philip

+0

Bởi vì tôi có nghĩa là một cái gì đó trong các hình thức của 'mới Foo > ' – Philip

+0

@Phillip Các khối mã đầu tiên và thứ ba là khá nhiều như nhau. Đầu tiên, '?' Có thể được thay thế bằng 'Object',' Mal', 'SubclassOfMal',' SubSubclassOfMal', v.v. Đối với cái thứ ba, '?' Có thể được thay thế bằng bất kỳ cái nào ở trên ngoại trừ 'Object'. Vẫn còn một số lượng thực tế vô hạn có thể khớp với '?', Và trình biên dịch không thể xử lý được. – Jeffrey

1

new Foo<?> có thể được thay thế tương đương với new Foo<SomeRandomTypeIMadeUp> trong đó SomeRandomTypeIMadeUp là bất kỳ loại nào đáp ứng được giới hạn của thông số loại đó. Lựa chọn đơn giản nhất là chỉ cần chọn giới hạn trên của thông số loại đó, ví dụ: nếu nó là class Foo<T extends X> thì new Foo<X> sẽ đủ.

Bạn có thể hỏi, tại sao tôi chỉ có thể chọn bất kỳ thông số loại tùy ý nào, ngay cả thông số có thể hoàn toàn không có kết nối với phần còn lại của chương trình của tôi? Không phải là không an toàn sao? Câu trả lời là không, bởi vì đó là chính xác những gì Foo<?> có nghĩa là - các tham số kiểu có thể là bất cứ điều gì, và bạn không thể phụ thuộc vào nó là gì. Điều này thể hiện sự ngớ ngẩn tuyệt đối của những gì bạn đang yêu cầu. Một cái gì đó được tạo ra với new Foo<?> sẽ là khá nhiều hoàn toàn vô ích, bởi vì bạn không thể làm bất cứ điều gì với nó mà phụ thuộc vào loại tham số kiểu.

Các loại có ký tự đại diện thường hữu ích. Ví dụ: bạn có thể có một đối số thuộc loại List<?> và bạn có thể chuyển bất kỳ loại List nào cho nó và nó chỉ đơn giản là lấy nội dung ra khỏi danh sách. Nhưng trong trường hợp đó, bạn không tạo danh sách. Chức năng tạo danh sách và chuyển nó cho bạn có thể có một số tham số kiểu không ký tự đại diện. Trong phạm vi chức năng đó, bạn vẫn có thể đưa mọi thứ vào danh sách và làm những việc hữu ích với nó. Nếu một hàm được tạo ra List<?>; điều này sẽ khá vô ích - bạn không thể đặt bất kỳ phần tử nào trừ null vào nó.

Đây là lý do tại sao bạn không được phép làm new Foo<?>: Hoàn toàn vô dụng; bạn có thể sử dụng Generics sai nếu bạn muốn sử dụng nó. Và trong trường hợp cực kỳ hiếm hoi bạn thực sự muốn nó, có sẵn một sự thay thế sẵn sàng, new Foo<AnyTypeThatSatisfiesTheBounds>.

Foo<Bar<?>> rất khác. Bar<?> là loại cụ thể. Foo<Bar<?>> không có nghĩa là bạn có thể gán Foo<Bar<Something>> cho nó; thay vào đó, đó là bất hợp pháp; các thông số loại của Foo phải khớp với nhau nếu chúng không phải là ký tự đại diện. Cũng không giống như với một ký tự đại diện, với một List<Bar<?>>, bạn có thể đặt các đối tượng vào nó và đưa các đối tượng ra khỏi nó.

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