2011-11-07 69 views
10

Giả sử T là tham số kiểu lớp, tại sao tôi không thể sử dụng T.classTên lớp của các tham số kiểu trong java?

Tôi đã viết một hàm tải xuống trang và phân tích cú pháp theo lớp đã qua. Đối với phân tích cú pháp, tôi sử dụng một chức năng có chữ ký là: ParseObject::parse(Class<T> classname)

<T> void downloadParse(){ 
    ParseObject obj; 
    obj.parse(T.class); //<--- why compiler error here?? (whereas something like Integer.class is allowed) 
} 
+2

trả lời ngắn gọn: 'loại tẩy xoá. Google có thể làm phần còn lại :) – laher

Trả lời

15

Java Generics được thực hiện thông qua type erasure. Chúng chỉ có thể được sử dụng để kiểm tra thời gian biên dịch. Sau khi kết hợp, đối tượng được thay đổi thành đối tượng chung thấp nhất. (Trong trường hợp này là Object.class).

Bytecode được biên dịch không biết T là gì.

Nếu bạn muốn truy cập vào các lớp, bạn cần phải thay đổi phương thức để:

<T> void downloadParse(Class<T> cls){ 
    ParserObject obj; 
    obj.parse(cls); 
} 
+0

QUICK NHANH !! Cảm ơn!! bạn đánh bại người đàn ông google :) Không hiểu câu trả lời 100%, sẽ google nhiều hơn nữa. btw Tôi đã làm điều tương tự như gợi ý. Chỉ có tôi cần phải chuyển tham số 'cls' xung quanh một số hàm và lưu nó vào một biến lớp trong chương trình thực tế của tôi. (cảm thấy kỳ lạ khi làm điều đó) –

+1

Đó là loại kỳ lạ, nhưng đó là cách duy nhất để làm điều đó. Nếu Java bao giờ có được generics reified, nó sẽ làm cho cuộc sống nhiều, dễ dàng hơn nhiều. –

+4

Không có nhiều ý nghĩa trong việc sử dụng này mặc dù. Đơn giản chỉ cần sử dụng 'Class ' cho cùng một hiệu ứng. Nó chỉ có ý nghĩa nếu bạn cần thực thi một số loại, ví dụ: '> void dp (Lớp cls)'. Một quy tắc tốt cho thump cho generics: cố gắng tránh chúng càng lâu càng tốt;) – sfussenegger

2

Erasure là nhân vật phản diện ở đây. Từ các hướng dẫn Java:

Ví dụ, Hộp được phiên dịch sang gõ Box, được gọi là loại thô - một kiểu thô là một lớp hoặc giao diện tên generic mà không bất kỳ đối số kiểu. Điều này có nghĩa rằng bạn không thể tìm ra loại Đối tượng một lớp chung được sử dụng trong thời gian chạy. Các hoạt động sau là không thể:

public class MyClass<E> { 
    public static void myMethod(Object item) { 
     if (item instanceof E) { //Compiler error 
      ... 
     } 
     E item2 = new E();  //Compiler error 
     E[] iArray = new E[10]; //Compiler error 
     E obj = (E)new Object(); //Unchecked cast warning 
    } 
} 

Các hoạt động được in đậm là vô nghĩa khi chạy vì trình biên dịch loại bỏ tất cả các thông tin về loại tranh luận thực tế (đại diện bởi các tham số kiểu E) tại thời gian biên dịch.

Với Erasure, các loại thông tin được lấy ra, và tất cả mọi thứ chỉ là một đối tượng:

Khi một kiểu generic được khởi tạo, trình biên dịch chuyển những loại bởi một kỹ thuật gọi là loại tẩy xoá - một quá trình nơi trình biên dịch xóa tất cả thông tin có liên quan đến các thông số loại và nhập các đối số trong một lớp hoặc phương thức. Kiểu xóa cho phép các ứng dụng Java sử dụng Generics để duy trì khả năng tương thích nhị phân với Các thư viện và ứng dụng Java đã được tạo trước khi Generics.

Sau đó trình biên dịch giới thiệu lại lớp "T" làm phôi ở mọi nơi được yêu cầu. T không "tồn tại" bên trong chung, vì vậy bạn không thể tạo một đối tượng của lớp T. Trên các cuộc gọi vào và ra khỏi chung chung, trình biên dịch đưa các đối tượng vào lớp "T".

Google "tẩy xoá java" để biết thêm thông tin về cách hoạt động của tính năng này. Wikipedia cung cấp some examples.

2

Như những người khác đã nói, điều đó là không thể. Nhưng vì đó là một phương pháp không có đối số và trả về khoảng trống, bạn mong đợi T là gì?

Something bạn có thể gặp một lần trong một thời gian là thế này:

<T> T foo(Class<T> cls) { 
    Object o = ...; 
    return cls.cast(o); 
} 

// usage - perfectly type safe 
String s = foo(String.class); 

Bên cạnh đó, đôi khi có thể để có được lập luận kiểu generic, ví dụ ở đây:

class Foo implements Iterable<String> { 
    // snip 
} 

ParameterizedType pt = (ParameterizedType) Foo.class.getGenericInterfaces()[0]; 
System.out.println(pt); // prints java.lang.Iterable<java.lang.String> 

Class<?> at = (Class<?>) pt.getActualTypeArguments()[0]; 
System.out.println(at.getName()); // prints java.lang.String 

Nhưng đó là một câu chuyện;)

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