2011-12-09 26 views
9

Có cách nào có thể tránh loại xóa và truy cập thông số loại không?Tránh loại tẩy xóa Java

public class Foo<T extends Enum<?> & Bar> { 
    public Foo() { 
     // access the template class here? 
     // i.e. : 
     baz(T.class); // obviously doesn't work 
    } 

    private void baz(Class<T> qux) { 
     // do stuff like 
     T[] constants = qux.getEnumConstants(); 
     ... 
    } 
} 

Tôi cần biết về T và làm những việc với nó. Là nó có thể, và nếu như vậy, làm thế nào nó có thể được thực hiện mà không cần đi qua trong lớp trong constructor hoặc bất cứ nơi nào ngoài các tham số?

EDIT: Mục đích chính của câu hỏi này là để tìm hiểu xem có bất kỳ cách thực tế nào xung quanh loại xóa.

Trả lời

5

AFACT, có không cách thiết thực xung quanh loại tẩy xoá bởi vì bạn không thể yêu cầu một cái gì đó mà bộ thực thi không có quyền truy cập vào. Giả sử tất nhiên bạn đồng ý rằng các lớp chung của lớp con cho mỗi enum thực hiện giao diện Bar là một công việc thực tế xung quanh.

enum Test implements Bar { 
    ONE, TWO 
} 

class Foo<T> extends FooAbstract<Test> { 
    public Foo() { 
     ParameterizedType genericSuperclass = 
       (ParameterizedType) getClass().getGenericSuperclass(); 
     baz((Class<T>) genericSuperclass.getActualTypeArguments()[0]); 
    } 

    private void baz(Class<T> qux) { 
     T[] constants = qux.getEnumConstants(); 
     System.out.println(Arrays.toString(constants)); // print [ONE, TWO] 
    } 
} 

interface Bar { 
} 

class FooAbstract<T extends Enum<?> & Bar> { 
} 
+2

+1 Yep - Đây là một giải pháp dựa trên sự phản chiếu khác nếu bạn thích lớp con để truyền đối tượng 'Lớp'. –

2

Nếu bạn sẵn sàng/có thể trao một mã thông báo lớp học để các nhà xây dựng:

public Foo(Class<T> clazz) { 
    baz(clazz); 
} 

private void baz(Class<T> qux) { 
    // ... 
} 

Bằng cách đó, bạn có thể tạo ra các đối tượng của loại T với Class.newInstance(), nỗ lực để cast đối tượng tùy ý để T sử dụng Class.cast(), v.v.

Bạn định làm gì trong baz()?

+0

Giả sử nó yêu cầu lớp đã cho danh sách giá trị và sử dụng các giá trị đó. Đi qua lớp không phải là điều tôi muốn làm. –

1

Như pholser chỉ ra trong câu trả lời của mình, cách duy nhất để đạt được điều này là bằng cách chuyển trong đối tượng Class đại diện cho loại T. Đó là vì Type Erasure rằng không thể xóa T.classT bị xóa trước khi chạy.

Bạn có vẻ kháng cự khi vượt qua đối tượng Class, nhưng đó là cách duy nhất để sử dụng phương thức getEnumConstants(). Đây là một chứa tự ví dụ:

public class Foo<T extends Enum<?> & Bar> { 

    final Class<T> clazz; 

    public Foo(Class<T> clazz) { 

     this.clazz = clazz; 
    } 

    public void baz() { 

     T[] constants = clazz.getEnumConstants(); 

     System.out.println(Arrays.toString(constants)); 
    } 

    public static void main(String[] args) { 

     new Foo<MyEnum>(MyEnum.class).baz(); //prints "[A, B, C, D]" 
    } 
} 

public interface Bar { } 

public enum MyEnum implements Bar { A, B, C, D; } 
+2

Vì vậy, hoàn toàn không có cách nào để tôi có được xung quanh Type Erasure và tìm ra lớp được truyền vào như 'T'?Ý tưởng của chủ đề này là để tìm ra nếu có bất kỳ cách nào xung quanh loại tẩy xoá. –

+1

@Chris - Phản ánh là giải pháp thay thế duy nhất để loại xóa trong Java. Nhưng bạn không bị bất lợi nhiều hơn từ những gì bạn có bằng cách truyền vào đối tượng 'Class', mặc dù nó gây phiền nhiễu và trông thừa trong thời gian biên dịch. Lưu ý rằng bạn đã dựa vào sự phản chiếu bằng cách sử dụng 'Class # getEnumConstants()'. Cách thay thế duy nhất là thiết kế lại hoàn chỉnh, loại bỏ sự phụ thuộc của bạn vào phương pháp đó. –

1

Sử dụng mã thông báo loại siêu như đề xuất bởi Neil Gafter và được sử dụng bởi thư viện như guice cho mục đích này.

Xem http://gafter.blogspot.com/2006/12/super-type-tokens.html cho mô tả ban đầu và tôi đã kiểm tra nguồn guice để thực hiện công việc của cuộc sống vô tuyến CA.

có một q trong đó có một câu trả lời với ví dụ làm việc inline đây How can I pass a Class as parameter and return a generic collection in Java?

0

Trong một số trường hợp, bạn có thể sử dụng một cách giải quyết đề nghị của Richard Gomes. Khi tạo các thể hiện của các lớp ẩn danh, thông tin lớp tham số kiểu có sẵn.

class A<T> 
{ 
    A() 
    { 
     java.lang.reflect.ParameterizedType parameterizedType = (java.lang.reflect.ParameterizedType) (this.getClass().getGenericSuperclass()); 
     System.out.println(parameterizedType.getActualTypeArguments()[0]); 
    } 
} 

public class Example { 
public static void main(String[] args) { 
    A<String> anonymous = new A<String>() {}; // prints java.lang.String 
} 
} 

Lưu ý rằng nhiều trường hợp tạo ra theo cách này sẽ được các lớp ẩn danh khác nhau, và nếu đó là một vấn đề bạn có thể muốn có một A_String_Factory lớp với một createNew() chức năng dựa trên bản sao để thay thế cho các cuộc gọi đến mới.

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