2010-03-02 28 views
15

Tôi đã học và thử nghiệm với Java Generics trong một thời gian nhưng tôi đã chạy vào một cái gì đó mà tôi không thể giải thích. Lấy ví dụ đoạn mã sau:Các lớp bên trong được nhập chung trong Java

public class Question { 
    public <T> Sub<T> getSub(Class<T> c) { 
     return new Sub<T>(c); 
    } 
    public class Sub<S> { 
     private Class<S> c; 
     public Sub(Class<S> c) { 
      this.c = c; 
     } 
     public void add(S s) { 
     } 
    } 
} 

Và mã kiểm tra:

import generics.Question.Sub; 

public class Answer { 
    public static void main(String [] args) { 
     Question q = new Question(); 
     Sub<String> s = q.getSub(String.class); 
     s.add(""); 
    } 
} 

Khi điều này được chạy nó đưa ra một thông báo lỗi tuyệt vời khó hiểu:

C:\Answer.java:8: incompatible types 
found : generics.Question.Sub<java.lang.String> 
required: generics.Question.Sub<java.lang.String> 
     Sub<String> s = q.getSub(String.class); 
1 error 

Bây giờ, thông qua một số thử nghiệm Tôi đã làm việc ra làm thế nào để ngăn chặn lỗi trình biên dịch. Tôi có thể làm cho lớp Sub trở thành lớp bên trong tĩnh, hoặc tôi cần tham khảo lớp Sub như Question.Sub <String>. Những gì tôi không thể làm là giải thích tại sao tôi cần phải làm điều này.

Tôi đã thực hiện một số đọc tài liệu Java về Generics nhưng không bao gồm trường hợp cụ thể này.

Mọi người có thể giải thích tại sao mã này là loại không tương thích trong biểu mẫu hiện tại không?

-Edit-

Nhìn vào điều này gần hơn tôi có thể thấy rằng tôi nhận được cùng một hành vi bên ngoài Netbeans. Nếu tôi có mã trong cấu trúc sau:

generics\ 
generics\Question.java 
generics\Answer.java 

Khi tôi biên dịch các tập tin với nhau, tôi không nhận được lỗi:

C:\>javac generics\Question.java generics\Answer.java 

C:\> 

Tuy nhiên, khi tôi lập Câu hỏi đầu tiên và sau đó trả lời, tôi gặp lỗi:

C:\>javac generics\Question.java 

C:\>javac generics\Answer.java 
generics\Answer.java:8: incompatible types 
found : generics.Question.Sub<java.lang.String> 
required: generics.Question.Sub<java.lang.String> 
     Sub<String> s = q.getSub(String.class); 
           ^
1 error 

Tôi đã nghe một số điều được đề cập về Loại xóa. Đây có phải là trường hợp trong tình huống này không?

+0

Mã này hoạt động đối với tôi trong Eclipse. Bạn đang sử dụng IDE/trình biên dịch nào? – polygenelubricants

+0

Tôi cũng có thể biên dịch điều này mà không gặp sự cố khi sử dụng phiên bản java "1.6.0_15" – Steen

+0

Netbeans 6.7.1 với JDK 1.5.0_14. Nếu tôi biên dịch nó bên ngoài Netbeans, tôi đồng ý, nó biên soạn tốt. Tôi sẽ điều tra thêm. Cảm ơn vì bạn đã phản hồi. – gencoreoperative

Trả lời

1

Loại tẩy xoá là thuộc tính của cách các generics hiện đang được triển khai trong Java. Điều này có nghĩa là loại biến chỉ được biết ở thời gian biên dịch, nhưng không phải lúc chạy. Vì vậy, ví dụ: trong các trường hợp sau:

Map<String,String> map = new HashMap<String,String>(); 

thì trình biên dịch sẽ biết kiểm tra các mục được đặt tại cơ sở Chuỗi/Chuỗi. Tuy nhiên, mã được biên dịch không biết gì về Chuỗi, Chuỗi - bạn vẫn có thể chèn các đối tượng vào với loại sai, ví dụ:

Map other = (Map)map; 
other.put(new Integer(3), new Double(4.5); 

Vấn đề là mã được biên dịch không kiểm tra các loại đối số khi truyền vào, và cũng không phải thời gian chạy (vì thông tin kiểu đã bị xóa, do đó, hãy loại bỏ xoá).

Tôi nghi ngờ rằng loại tẩy xoá là một vấn đề ở đây - kể từ lúc biên dịch, bạn có đầy đủ thông tin về loại - nhưng đúng hơn là nó có thể là một lỗi. Có khá nhiều vấn đề về lông với generics (từ một thực hiện) và có các trình biên dịch khác nhau được sử dụng với JavaC và Eclipse, do đó có thể hiển thị các lỗi khác nhau. Trong một số trường hợp, trình biên dịch Eclipse đã trung thành với spec hơn trình biên dịch Sun (vì vậy Eclipse tạo ra các lỗi trong khi Sun không) và nó chủ yếu là do sự phức tạp của cách mà hệ thống kiểu hoạt động.

Vì vậy, rất có thể là một (hoặc nhiều) lỗi có chứa generics trong trình biên dịch 1.5.0_14 ...

+0

Tôi có thể xác nhận đây là trường hợp, xem bên dưới: C: \> javac -version javac 1.6.0_18 C: \> javac src \ generics \ Question.java C: \> javac src \ generics \ Answer. java -cp src Hoạt động tốt. Cảm ơn bạn! – gencoreoperative

+0

Thực ra "Điều này có nghĩa là loại biến chỉ được biết ở thời gian biên dịch, nhưng không phải lúc chạy.": Thông tin Kiểu có sẵn khi chạy và có sẵn bằng cách sử dụng sự phản chiếu. Trong các tệp lớp, các kiểu generic vẫn được giữ lại (nó sẽ biên dịch như thế nào đối với một lớp bên ngoài với các generic), do đó "loại tẩy xoá" không xóa các loại khỏi lớp, chỉ từ thời gian chạy. – Pindatjuh

+0

Để rõ ràng; thông tin về các kiểu generic được lưu trữ trong các chú thích trên lớp, nhưng không được lưu trữ trên các kiểu của phương thức. Vì vậy, bất kỳ cuộc gọi không chung chung nào vẫn có thể được sử dụng với nó; tuy nhiên, các chú thích chỉ được trình biên dịch sử dụng tại thời gian biên dịch. Vì vậy, chúng không thực sự là một phần của thời gian chạy, ngay cả khi bạn có thể quan sát tệp lớp lúc chạy. – AlBlue

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