2013-01-12 28 views
7

Hãy tưởng tượng lớp này:Generic constructor (Lớp <T> clazz) không hỗ trợ T trong đó T là một Generics

public class ObjectCreator<T> { 
    private Class<T> persistentClass; 

    public ObjectCreator(Class<T> persistentClass) { 
     this.persistentClass = persistentClass; 
    } 

    public T create() { 
     T instance = null; 
     try { 
      instance = persistentClass.newInstance(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return instance; 
    } 
} 

Bây giờ tôi sublclass nó với một đối tượng tên miền:

public class PersonCreator extends ObjectCreator<Person>{ 

    /** 
    * @param persistentClass 
    */ 
    public PersonCreator() { 
     super(Person.class); 

    } 

} 

Tất cả các công trình lớn. .. Nhưng nếu tôi cố gắng phân lớp nó với một đối tượng miền chung chung khác, trình biên dịch sẽ phàn nàn:

public class MessageCreator extends ObjectCreator<Message<String>>{ 

    /** 
    * @param persistentClass 
    */ 
    public MessageCreator() { 
     super(Message.class); 
    } 

} 

Các constructor ObjectCreator<Message<String>>(Class<Message>) là undefined MessageCreator.java

Tôi nghĩ rằng đây là một hạn chế lớn: tại sao điều này là cấm?

Bất kỳ ý tưởng nào về cách làm việc xung quanh?

Massimo

Trả lời

3

Hãy thử điều này:

super((Class<Message<String>>) ((Object) Message.class)); //compiles with warning 

Sẽ tốt hơn nếu bạn thay đổi hàm tạo của lớp cơ sở thành

public ObjectCreator(Class<? extends T> persistentClass) 

và sau đó sử dụng này trong các lớp derrived:

super(new Message<String>(){}.getClass()); //compiles without warning 

Nó sẽ biên dịch mà không cần cảnh báo

EDIT

Theo định nghĩa của getClass() ()

Returns Class<? extends X>, trong đó X là xóa của loại tĩnh của biểu thức mà getClass được gọi. Điều đó có nghĩa getClass() sẽ trở lại Class<? extends Message> cho new Message<String>()Class<? extends Message<String>> cho lớp ẩn danh new Message<String>(){}

+0

Trừ khi 'Message' là' final' hoặc có một hàm tạo mặc định không thể truy cập được. –

+0

@PaulBellora có, đây là giới hạn được biết đến của phương pháp này. Tuy nhiên tôi không thấy bất kỳ giải pháp nào khác sẽ biên dịch mà không cần cảnh báo. –

+0

Đó là giải pháp tốt nhất mà tôi nghĩ. Một câu hỏi: đó là sự khác biệt giữa Thông báo mới () và Thư mới () {}? –

1

Không có biến thể' .class' cho các lớp học chung - thông tin không có sẵn tại thời gian chạy, hovewever để làm cho mã biên dịch trên, bạn chỉ có thể đúc các biểu thức để loại theo yêu cầu.

super ((Class<Message<String>>)((Class<?>)Message.class)); 

Lưu ý rằng điều này sẽ không làm cho các thông tin có sẵn trong thời gian chạy một trong hai (ví dụ: đối với phản ánh, vv), tuy nhiên nó sẽ biên dịch với một cảnh báo không được kiểm soát - mà chỉ có nghĩa là - một cảnh báo.

+0

Điều đó không có biên dịch. – assylias

+2

super ((Class >) ((Class ) Thông báo.lớp học)); Điều này làm – Leonidos

+0

Xin lỗi, tôi đã không kiểm tra câu trả lời của tôi, đầu tiên - Leonidos là chính xác - trước tiên bạn cần phải đưa Message.class đến 'Class ' và sau đó thực hiện các yêu cầu cast. Đã cập nhật câu trả lời của tôi. – Sebastian

0

Nó hoạt động nếu bạn chỉ cần sử dụng

public class MessageCreator extends ObjectCreator<Message>{ 

    /** 
    * @param persistentClass 
    */ 
    public MessageCreator() { 
     super(Message.class); 
    } 

} 

Điều này tạo ra các đối tượng đúng nhưng vẫn sẽ đưa ra một cảnh báo cho các định nghĩa lớp và nếu bạn làm

Message<String> m = creator.create(); 
Các vấn đề liên quan