Bộ sưu tập.emptyList () trả về Danh sách <Object>?


269

Tôi gặp một số khó khăn khi điều hướng quy tắc của Java để suy ra các tham số loại chung. Hãy xem xét các lớp sau, có một tham số danh sách tùy chọn:

import java.util.Collections;
import java.util.List;

public class Person {
  private String name;
  private List<String> nicknames;

  public Person(String name) {
    this(name,Collections.emptyList());
  }

  public Person(String name,List<String> nicknames) {
    this.name = name;
    this.nicknames = nicknames;
  }
}

Trình biên dịch Java của tôi đưa ra lỗi sau:

Person.java:9: The constructor Person(String, List<Object>) is undefined

Nhưng Collections.emptyList()trả về loại <T> List<T>, không List<Object>. Thêm một diễn viên không giúp đỡ

public Person(String name) {
  this(name,(List<String>)Collections.emptyList());
}

sản lượng

Person.java:9: inconvertible types

Sử dụng EMPTY_LISTthay vìemptyList()

public Person(String name) {
  this(name,Collections.EMPTY_LIST);
}

sản lượng

Person.java:9: warning: [unchecked] unchecked conversion

Trong khi đó, thay đổi sau đây sẽ khiến lỗi không còn nữa:

public Person(String name) {
  this.name = name;
  this.nicknames = Collections.emptyList();
}

Bất cứ ai cũng có thể giải thích quy tắc kiểm tra loại nào tôi đang chạy theo ở đây, và cách tốt nhất để làm việc xung quanh nó? Trong ví dụ này, ví dụ mã cuối cùng là thỏa đáng, nhưng với các lớp lớn hơn, tôi muốn có thể viết các phương thức theo mẫu "tham số tùy chọn" này mà không cần sao chép mã.

Đối với tín dụng bổ sung: khi nào thì thích hợp để sử dụng EMPTY_LISTtrái ngược với emptyList()?


1
Đối với tất cả các câu hỏi liên quan đến Generics Java, tôi đánh giá cao " Bộ sưu tập và bộ sưu tập Java " của Maurice Naftalin, Philip Wadler.
Julien Chastang

Câu trả lời:


447

Vấn đề bạn gặp phải là mặc dù phương thức emptyList()trả về List<T>, nhưng bạn chưa cung cấp loại đó, vì vậy nó mặc định trả về List<Object>. Bạn có thể cung cấp tham số loại và mã của bạn hoạt động như mong đợi, như thế này:

public Person(String name) {
  this(name,Collections.<String>emptyList());
}

Bây giờ khi bạn đang thực hiện gán thẳng, trình biên dịch có thể tìm ra các tham số loại chung cho bạn. Nó được gọi là suy luận kiểu. Ví dụ: nếu bạn đã làm điều này:

public Person(String name) {
  List<String> emptyList = Collections.emptyList();
  this(name, emptyList);
}

sau đó emptyList()cuộc gọi sẽ trả lại chính xác a List<String>.


12
Hiểu rồi. Đến từ thế giới ML, đối với tôi, thật kỳ lạ khi Java không thể suy ra đúng loại: loại tham số chính thức và loại trả về của danh sách trống rõ ràng là không thể xác định được. Nhưng tôi đoán loại suy ra chỉ có thể thực hiện "các bước bé".
Chris Conway

5
Trong một số trường hợp đơn giản, trình biên dịch dường như có thể suy ra tham số loại bị thiếu trong trường hợp này - nhưng điều này có thể nguy hiểm. Nếu nhiều phiên bản của phương thức tồn tại với các tham số khác nhau, cuối cùng bạn có thể gọi sai. Và cái thứ hai thậm chí có thể chưa tồn tại ...
Bill Michell

13
Ký hiệu "Bộ sưu tập. <String> blankList ()" thực sự lạ, nhưng có ý nghĩa. Dễ dàng hơn Enum <E kéo dài Enum <E >>. :)
Thiago Chaves

12
Việc cung cấp một tham số kiểu không còn cần thiết trong Java 8 nữa (trừ khi có sự không rõ ràng trong các kiểu chung có thể).
Vitalii Fedorenko

9
Đoạn mã thứ hai hiển thị kiểu suy luận độc đáo, nhưng sẽ không biên dịch, tất nhiên. Cuộc gọi đến thisphải là câu lệnh đầu tiên trong hàm tạo.
Arjan

99

Bạn muốn sử dụng:

Collections.<String>emptyList();

Nếu bạn nhìn vào nguồn cho những gì rỗngList bạn có thấy rằng nó thực sự chỉ làm một

return (List<T>)EMPTY_LIST;

26

phương thức blankList có chữ ký này:

public static final <T> List<T> emptyList()

Điều đó <T>trước Danh sách từ có nghĩa là nó xâm nhập giá trị của tham số chung T từ loại biến mà kết quả được gán cho. Vì vậy, trong trường hợp này:

List<String> stringList = Collections.emptyList();

Giá trị trả về sau đó được tham chiếu rõ ràng bằng một biến kiểu List<String>, vì vậy trình biên dịch có thể tìm ra nó. Trong trường hợp này:

setList(Collections.emptyList());

Không có biến trả về rõ ràng cho trình biên dịch sử dụng để tìm ra loại chung, vì vậy nó mặc định là Object.

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.