2013-06-19 24 views
12

Tôi không hiểu lỗi trình biên dịch xuất phát từ mã sau đây. Tôi xác định giao diện chung, xem Tác vụ, với hai phương pháp: U doSomething(String value)List<Integer> getIDs(). Phương thức doSomething() thực sự sử dụng kiểu generic như kiểu giá trị trả về của nó, nhưng dường như không gây ra vấn đề gì. Phương thức getIDs() trả về một Danh sách, không liên quan đến loại Tác vụ, nhưng nó gây ra các vấn đề khi sử dụng lệnh for..each để lặp lại giá trị trả về. Lỗi trình biên dịch sau xảy ra.Lỗi trình biên dịch trên giao diện chung Java với phương thức List <>

error: incompatible types 
    for (Integer value : task.getIDs()){ 
required: Integer 
found: Object 

Dường như các loại tẩy xoá trên giao diện đang gây ra trình biên dịch để quên đi những kiểu được khai báo theo phương pháp thứ hai, đó là không liên quan đến các loại generic. Hay nói cách khác là loại chung trên giao diện ảnh hưởng đến cách trình biên dịch hiểu giá trị trả về theo phương pháp getIDs() và cụ thể trong ngữ cảnh của câu lệnh for..each?

Dường như tôi có tham chiếu đến danh sách bên ngoài for..each không có vấn đề gì, nhưng không trực tiếp.

public class InterfaceTest { 
    public static void main(String[] args) { 
     Task task = new MyTask(); 
     // no complaints about the type here  
     List<Integer> values = task.getIDs(); 

     // getting a compiler error for this line 
     for (Integer value : task.getIDs()){ 

     } 
    } 
} 


interface Task<U>{ 
    U doSomething(String value); 
    List<Integer> getIDs(); 
} 

Việc thực hiện của giao diện là không cần thiết để chứng minh điểm, nhưng tôi không muốn để lại tài liệu tham khảo Task task = null; và có câu trả lời của nói với tôi đó là vấn đề.

class MyTask implements Task<Boolean>{ 

    @Override 
    public Boolean doSomething(String value) { 
     System.out.println(value); 
     return false; 
    } 

    @Override 
    public List<Integer> getIDs() { 
     return Arrays.asList(1, 2, 3, 4); 
    } 
} 
+0

Nó làm gì với 'return new int [] {1,2,3,4}', hoặc 'return Arrays.asList (new Integer (1), new Integer (2), ...);' ? (lưu ý, không phải giả định. hãy thử nó, thêm kết quả cho câu hỏi để cho thấy rằng boxing/unboxing rõ ràng đang làm điều gì đó kỳ lạ) –

+0

Đây là một câu hỏi rất hay; câu trả lời có lẽ là ẩn sâu trong ruột của JLS. – arshajii

+1

@arshajii: Bạn đã thay đổi 'U doSomething (String value)' từ 'U doSomething (U value)'? Tôi nghĩ rằng mã đăng không thực sự là những gì OP đang làm. –

Trả lời

7

gì đang xảy ra là khi sử dụng sử dụng một lớp (hoặc giao diện) với một tham số chung <T> nhưng tham khảo và thể hiện của mà không <T> (tức là raw loại) trình biên dịch xóa tất cả thông tin loại chung từ lớp. Điều này có thể do khả năng tương thích với mã nguồn trước 1.5, nơi bạn sẽ không thể sử dụng thông tin loại chung.

Hãy xem xét trường hợp bạn đang viết mã và biên dịch trên trình biên dịch Java 1.4. Bạn muốn sử dụng một thư viện mà làm cho việc sử dụng Generics. Khi bạn đề cập đến một kiểu từ thư viện có các tham số chung như một kiểu thô, trình biên dịch thực thi việc sử dụng không có các tham số chung.

EDIT:

Các JLS-4.8-210 ám chỉ này khi nó đề cập đến (tín dụng: zhong-j-yu):

Loại một constructor (§8.8), phương pháp dụ (§8.4, §9.4), hoặc trường không tĩnh (§8.3) M của một loại thô C không được kế thừa từ các siêu lớp hoặc siêu kết nối là loại thô tương ứng với việc xóa loại của nó trong khai báo chung tương ứng với C.

Điều này vẫn cảm thấy giống như một hình ảnh xác thực, nhưng có thể vì lý do nào đó.

+0

http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.8-210 Loại phương thức ... thể hiện ... của loại thô ... là loại thô ... – ZhongYu

+0

Tôi tin rằng tôi đã đặt thông số kỹ thuật JLS thích hợp., xem câu trả lời của tôi. – Kevin

3

Lỗi này có vẻ nằm ở đây:

Task task = new MyTask(); 

Bạn đã quên thêm Generics sau Task. Nó sẽ làm việc nếu bạn thay đổi nó thành một trong những:.

Task<Boolean> task = new MyTask(); 
Task<?> task = new MyTask(); 
+1

Câu hỏi đặt ra là tại sao nó không hoạt động như vậy. – arshajii

+0

@arshajii họ không có tài nguyên/thời gian để họ đưa ra một điều trị rất thô sơ với các loại thô. – ZhongYu

3

Nếu tôi giải thích Java Language Specification (. §4.6 Loại Erasure) một cách chính xác, đây là một "Gotcha" của ngôn ngữ:

Loại tẩy xoá cũng có bản đồ chữ ký (§8.4.2) của một nhà xây dựng hoặc phương thức cho chữ ký không có kiểu tham số hoặc biến kiểu. Việc xóa của một hàm tạo hoặc chữ ký phương thức là một chữ ký có cùng tên với s và xóa của tất cả các kiểu tham số chính thức được đưa ra trong s.

Tôi tin rằng điều này khẳng định rằng nếu bạn khai báo một kiểu (Task) được khai báo với một tham số chung (Task<U>) mà không cho biết thông số chung chung, tất cả các chức năng của nó cũng mất kiểu generic của họ, cho dù họ có liên quan hay không . Do đó, số task.getIDs() của bạn được giải thích bởi trình biên dịch khi trả lại số đơn giản là List, không phải là List<Integer>. Trình lặp cho điều đó, tất nhiên, tạo ra Objects, không phải Integers, gây ra lỗi trình biên dịch mà bạn nhìn thấy.

Lý do cho điều này có khả năng tương thích ngược với mã được tạo trước Java 1.5, khi các generics được giới thiệu.