2011-12-08 36 views
9

Tôi chỉ học được về vấn đề này fine looking syntaxLàm thế nào để có được loại chung loại khi không có tham số của nó?

Collections.<String>emptyList() 

để có được một sản phẩm nào List với các yếu tố đó được cho là loại String. nguồn Java trông như thế này:

public static final List EMPTY_LIST = new EmptyList<Object>(); 
: 
public static final <T> List<T> emptyList() { 
    return (List<T>) EMPTY_LIST; 
} 

Bây giờ nếu tôi mã một phương pháp theo cách đó mà loại generic không xuất hiện trong danh sách tham số, có cách nào làm thế nào tôi có thể truy cập vào các lớp học thực tế đó trở thành T?

tôi nói, đến nay cách tiếp cận của tôi để mã điều tương tự có thể đã được

private <T> T get(String key, Class<T> clazz) { 
    // here I can do whatever I want with clazz, e.g.: 
    return clazz.cast(value); 
} 

Nếu tôi loại bỏ các clazz -parameter tôi sẽ không thể làm cast(). Rõ ràng tôi có thể làm

return (T) value; 

nhưng điều đó mang lại cho tôi cảnh báo thông thường Type safety: Unchecked cast from Object to T. Ok, @SuppressWarnings("unchecked") giúp ở đây, nhưng thực sự tôi muốn làm điều gì đó với kiểu trả về dự định của phương thức. Nếu tôi thêm biến cục bộ

T retValue; 

Tôi phải khởi tạo nó bằng một cái gì đó, null không giúp ích gì. Sau khi tôi chỉ định nó như

@SuppressWarnings("unchecked") 
T retValue = (T) value; 

Tôi có thể làm, ví dụ:

retValue.getClass().getName() 

nhưng nếu diễn viên không thành công, tôi sẽ không có thông tin về số T nữa.

Vì Java (hoặc ít nhất là Java 6 của tôi) không có thông tin chung nữa trong thời gian chạy, tôi hiện không thể nghĩ ra cách để thực hiện việc này. Là có một cách? Hay tôi phải gắn bó với cách tiếp cận "cũ" của tôi ở đây?

Xin lưu ý rằng ví dụ tôi xếp hàng rất đơn giản và không có ý nghĩa nhiều. Tôi muốn làm những thứ phức tạp hơn ở đây, nhưng đó là ngoài phạm vi.

+0

trông giống như một bản sao của [câu hỏi này] (http://stackoverflow.com/questions/2434041/instantiating-generics-type-in-java) –

+0

@NitzanVolman: Ở một mức độ nhất định bạn là đúng, nhưng không phải hoàn toàn. – sjngm

Trả lời

5

Nếu bạn muốn loại chung khi chạy, bạn cần có trường đó hoặc tạo một lớp con của loại cho một kết hợp loại cụ thể.

ví dụ:

List<String> list = new ArrayList<String>() {}; // creates a generic sub-type 
final Class type = (Class) ((ParameterizedType) list.getClass() 
          .getGenericSuperclass()).getActualTypeArguments()[0]; 
System.out.println(type); 

in

class java.lang.String 
+0

Thật tuyệt, tôi không biết về điều đó. –

+1

tức là bạn không thể có được loại chung của một lớp học, nhưng có thể nhận được các loại siêu lớp (và siêu giao diện) –

+0

@PeterLawrey: Whow, cảm ơn. Tuy nhiên, nếu tôi sử dụng danh sách 'List = new ArrayList () {};' nó không hoạt động. 'getActualTypeArguments() [0]' là một 'sun.reflect.generics.reflectiveObjects.TypeVariableImpl'. Điều đó có ý nghĩa? – sjngm

1

Như bạn đã đề cập, Generics Java chỉ là thời gian xây dựng. Chúng không được sử dụng trong thời gian chạy.

Do đó, cách tiếp cận cũ mà bạn đang sử dụng sẽ là cách duy nhất của bạn để thực hiện việc này.

4

Bạn không thể, thật không may. Tất cả các thông số chung và loại được xóa trong thời gian chạy. Vì vậy, trong thời gian chạy, loại T của bạn chỉ đơn giản là Object

+2

Đồng ý, tôi có một số phương pháp như 'private T nhận được (String key, Class clazz)' vì điều này. – Dave

2

retValue.getClass().getName() sẽ luôn trả về kiểu thời gian chạy của đối tượng chứ không phải tên lớp của loại thông số.

Nếu bạn muốn lấy lớp tham số, không có cách nào khác ngoài việc sử dụng giải pháp đầu tiên của bạn. (Có nghĩa là, vượt qua đối tượng lớp một cách rõ ràng.)

+0

Bạn nói đúng, đó sẽ là một tác dụng phụ khác mà tôi không muốn xảy ra. – sjngm

-2

tôi phát hiện ra rằng có một giải pháp cho việc Class<?> từ T:

public class Action<T>{ 
} 

public Class<?> getGenericType(Object action) throws ClassNotFoundException{ 
    Type type = 
    ((ParameterizedType)action.getClass().getGenericSuperclass()) 
     .getActualTypeArguments()[0]; 
    String sType[] = type.toString().split(" "); 

    if(sType.length != 2) 
     throw new ClassNotFoundException(); 

    return Class.forName(sType[1]); 
} 

Việc sử dụng mã trên:

Action<String> myAction = new Action<String>(); 

getGenericType(myAction); 

tôi đã không thử nghiệm điều này với mồi các loại itive (int, byte, boolean).

Tôi nghĩ rằng nó không phải là rất nhanh, nhưng bạn không phải vượt qua Class<?> để xây dựng.

EDIT:

Việc sử dụng trên là không đúng, bởi vì cha chung không có sẵn cho Action<String>. Lớp học chung chung sẽ chỉ có sẵn cho lớp được kế thừa như class ActionWithParam extends Action<String>{}. Đây là lý do tại sao tôi đã thay đổi ý định và bây giờ tôi đề nghị chuyển tham số lớp cho hàm tạo. Nhờ có newacct để chỉnh sửa.

+0

điều này là sai .. – newacct

+0

Điều gì là sai? Tôi biết rằng cần phải kiểm tra chiều dài và lặp lại trong ((ParameterizedType) action.getClass(). GetGenericSuperclass()) getActualTypeArgum‌ ents() và comparsion của sType [0] với "class". Tôi sử dụng điều này trong lời gọi phương thức từ xa tùy chỉnh của tôi và nó hoạt động. Xin vui lòng cho tôi một số gợi ý nếu có điều gì khác sai. – ivanesko

+0

mã như được hiển thị không "hoạt động" – newacct

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