2010-06-07 38 views
8

Đây có thể là một câu hỏi ngu ngốc, nhưng tôi chỉ thấy một câu hỏi yêu cầu how to create a Type variable for a generic type. Sự đồng thuận dường như là bạn nên có một phương pháp giả trở lại loại đó, và sau đó sử dụng sự phản ánh để có được nó (trong trường hợp này ông muốn Map<String, String>). Một cái gì đó như thế này:Tạo đối tượng kiểu được tham số bằng cách sử dụng lớp ẩn danh

public Map<String, String> dummy() { throw new Error(); } 

Type mapStringString = Class.forName("ThisClass").getMethod("dummy").getGenericReturnType(); 

Câu hỏi của tôi là, không có phản xạ sử dụng nhiều, có thể bạn không chỉ cần làm điều gì đó như:

Type mapStringString = new ParameterizedType() { 
    public Type getRawType() { 
     return Map.class; 
    } 

    public Type getOwnerType() { 
     return null; 
    } 

    public Type[] getActualTypeArguments() { 
     return new Type[] { String.class, String.class }; 
    } 
}; 

Sẽ làm việc này? Nếu không, tai sao không? Và một số các mối nguy hiểm/vấn đề là gì nếu nó (ngoài việc có thể để lại một số loại như Integer<String> mà rõ ràng là không thể.

+0

Tôi đang cố gắng làm những gì mà giải pháp đề xuất của bạn cho phép: lấy một loại tham số từ một nguyên Nhập và liệt kê các tham số Kiểu được cung cấp tại thời gian biên dịch. Bạn có tìm cách khác để làm điều này không? – user48956

Trả lời

6

Chắc chắn bạn có thể, và đối với hầu hết các ứng dụng nó có lẽ sẽ là đủ.

Ví dụ, sử dụng phương thức đầu tiên, bạn sẽ có được một đối tượng tinh tế hơn, ví dụ, bạn tạo một đối tượng type1 sử dụng phương thức đầu tiên, và type2 bằng phương thức thứ hai, sau đó type1.equals(type2) sẽ trả về giá trị true (vì phương thức đầu tiên trả về một đối tượng thực hiện đúng phương thức equals) nhưng type2.equals(type1) sẽ trả về false (vì trong phương thức thứ hai, bạn không ghi đè phương thức equals và đang sử dụng việc thực hiện từ Object).

Lý do tương tự áp dụng cho các phương pháp khác (đôi khi hữu ích) như toString, hashCode vv Phương pháp thứ hai không cung cấp các triển khai hữu ích trong số này.

+0

Thực tế type1's (sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl) thực hiện bằng bằng dường như truyền tham số bằng ParameterizedType và sau đó sử dụng các phương thức giao diện để so sánh các lớp, vì vậy 'type1.equals (type2)' sẽ trả về true, mặc dù ngược lại ('type2.equals (type1)') sẽ trả về false; bạn có thể thực hiện những điều đó, nhưng sau đó mã được một chút chunky –

+0

Chắc chắn. Bạn có thể nhận được kết quả tương tự trong phương pháp 2 như trong phương pháp 1, nhưng nó đòi hỏi một số công việc nhiều hơn, như bạn đã nhận thấy. – aioobe

2

Thực ra, tôi nghĩ cách đơn giản nhất (== ít mã) để làm điều này sẽ là giao diện giả mở rộng loại bạn quan tâm, và sau đó getGenericInterfaces()[0] từ lớp của nó (sử dụng getGenericSuperclass() nếu bạn quan tâm đến một lớp) :

private interface MapStringString extends Map<String, String> {} 
private static ParameterizedType mapStringString(){ 
    return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0]; 
} 

Mặc dù vậy, bạn phải tạo một lớp mới cho mỗi ParameterizedType bạn muốn đại diện. Tôi không thấy lý do tại sao triển khai của bạn sẽ không làm (trừ khi có thu hẹp phôi ở đâu đó), và nó có lợi ích hấp dẫn mà bạn có thể làm cho nó có thể tái sử dụng được.

+0

Trong khi điều này có vẻ là 'hackish' như phương pháp đầu tiên tôi đưa ra, ít nhất nó cung cấp mã tìm kiếm tốt hơn nơi bạn cố gắng lấy kiểu (chỉ cần gọi hàm thay vì làm get class, sau đó lấy phương thức, sau đó lấy kiểu trả về chung thời gian bạn muốn sử dụng nó). –

5

Nếu bạn bao gồm thư viện Guava của Google trong dự án của bạn (bạn nên; tuyệt vời), hãy sử dụng TypeToken để nhận loại. Thư viện Gson của Google (để tương tác với JSON) có số version tương tự. Cả hai đều được sử dụng như thế này (để có được một Type đại diện List<String>:

Type t = new TypeToken<List<String>>(){}.getType(); 

Nếu bạn không muốn dựa vào bất kỳ thư viện của bên thứ ba, bạn vẫn có thể sử dụng các loại vô danh để có được một generic bê tông loại với . một dòng mã (kỹ thuật này sẽ không làm việc với giao diện và có thể là nhiều rắc rối hơn nó có giá trị cho các loại Tóm tắt) để có được một Type đại diện HashMap<String, String>, làm điều này:

Type t = new HashMap<String, String>(){}.getClass().getGenericSuperclass(); 

tôi đã xác minh rằng kết quả Type dụ .equals() trường hợp Type được tạo bởi Gson 's TypeToken, mặc dù chưa được xác minh cho phiên bản TypeToken của Guava mà tôi không có quyền truy cập vào lúc này.(Ổi là một thư viện đa năng hơn rất tiện dụng cho tất cả mọi thứ, có lẽ bạn nên sử dụng nó.)

+0

Điều này vẫn yêu cầu Danh sách được biết đến lúc biên dịch. Trong OP, kiểu thô và kiểu tham số không biết cho đến khi biên dịch kiểu. – user48956

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