2011-07-06 39 views
7

Tôi muốn viết mã Java tương đương của mã C#.Java: Tạo đối tượng có loại là thông số loại

Mã của tôi C# như sau:

public abstract class A<T> where T : A<T>, new() 
{ 
    public static void Process() 
    { 
     Process(new T()); 
    } 

    public static void Process(T t) 
    { 
     // Do Something... 
    } 
} 

public class B : A<B> 
{ 
} 

public class C : A<C> 
{ 
} 

Java tương đương với mã của tôi trông như thế này.

public abstract class A<T extends A<T>> 
{ 
    public static <T extends A<T>> void process() 
    { 
     process(new T()); // Error: Cannot instantiate the type T 
    } 

    public static <T extends A<T>> void process(T t) 
    { 
     // Do Something... 
    } 

    public class B extends A<B> 
    { 
    } 

    public class C extends A<C> 
    { 
    } 
} 

Ở đây, cú pháp "mới()" trong lớp khai báo lớp khởi tạo để viết cấu trúc mặc định có thể gọi là "mới T()" từ lớp cơ sở. Nói cách khác khi tôi đang wrting lớp cơ sở tôi chắc chắn rằng lớp dẫn xuất sẽ có một constructer mặc định, để tôi có thể khởi tạo một đối tượng lớp dẫn xuất từ ​​lớp cơ sở.

Vấn đề của tôi trong Java là, tôi không thể khởi tạo đối tượng lớp dẫn xuất từ ​​lớp siêu. Tôi gặp lỗi "Cannot instantiate the type T" cho cuộc gọi "new T()". Có cách nào tương tự C# trong Java hay tôi nên sử dụng một cái gì đó giống như mẫu thử nghiệm và nhân bản?

Trả lời

5

Java không hỗ trợ reified generics, vì vậy không tương đương với "new T();". Cách tôi làm việc xung quanh này là sử dụng sự phản chiếu đối với một mã thông báo kiểu. Mã thông báo loại cho biết loại chung chung là gì.

public abstract class A<T> { 
    private Class<T> typeToken; 
    // constructor 
    public A() { 
     typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
    } 
} 

Sau đó, sử dụng phản chiếu để khởi tạo lớp học. Nó xấu xí, nhưng nó hoàn thành công việc.

+0

Cảm ơn bạn đã trả lời nhanh. Vì tôi đang cố gắng tạo một cá thể mới bên trong một phương thức tĩnh, tôi không thể thực hiện một cuộc gọi getClass(). Bên cạnh đó T.class không tồn tại beacuse xây dựng thời gian biên dịch. Vì vậy, phản ánh dường như không phải là một giải pháp cho tôi. Hoặc tôi không thể tìm thấy nó (: –

+0

Điều này sẽ chỉ hoạt động nếu lớp con sử dụng tham số kiểu cụ thể. Nếu lớp con là 'public class B mở rộng A ' ví dụ, điều này sẽ có cùng một vấn đề chính xác. tốt hơn để sử dụng các loại thẻ nhưng yêu cầu người gọi chuyển mã thông báo vào hàm tạo hoặc phương thức. –

0

Ngoài ra, hãy cẩn thận về điều này nếu bạn đang sử dụng Generics.

T[] someArray = new T[]; 

Đây là một lý do để thích ArrayList cho mảng. Lý do cho vấn đề nằm với khả năng tái tạo và loại xóa.

2

Bạn có thể tìm thấy một số giải thích về sự khác biệt giữa Generics trong C# và Java từ this li nk - comparing java and C# generics.

Generics Java là một cấu trúc hoàn toàn biên dịch. Bạn không thể làm bất cứ điều gì với các tham số kiểu chung mà dựa vào bất kỳ cách nào trên thông tin thời gian chạy. Điều này bao gồm:

  • trường Tạo kiểu generic tham số.
  • Tạo mảng các loại thông số chung .
  • Quering lớp thời gian chạy của tham số loại chung.
  • Sử dụng instanceof với thông số chung loại .

Bạn có thể bỏ qua giới hạn này với java.lang.reflect tên miền. Ví dụ: xem câu hỏi về lưu lượng truy cập stackoverflow này: Genercs and Class.forName()

0

Chỉ cần sử dụng mẫu Abstract Factory bog tiêu chuẩn. Sau đó, bạn nhận được các lợi ích bổ sung mà bạn không ràng buộc với một loại cụ thể, kiểu triển khai không cần phải có một hàm tạo cụ thể, cá thể có thể có một số tham số, các thể hiện có thể được lưu trữ, v.v.

Vì tình yêu của thần, đừng sử dụng sự phản chiếu.

0

Ngoài các nhận xét khác, tôi khuyên bạn không nên sử dụng Generics. Họ không cần thiết - họ bị tước bỏ thời gian biên dịch - và nếu bạn không biết rõ họ sẽ cố gắng làm cho họ làm những việc họ không thể.

Khi bạn có lớp học hoạt động bình thường, hãy sau đó thêm chúng trở lại. IDE của bạn vào thời điểm đó, cung cấp cho bạn rất nhiều lời khuyên hữu ích và dễ hiểu, và các generics sẽ cảnh báo bạn khi bạn sử dụng các đối tượng của sai lớp.

Có vẻ như có thể với tôi rằng lớp học này sẽ không cần generics chút nào khi hoàn tất. (Tôi không biết những gì khác lớp này có thể làm, và tôi không hiểu việc sử dụng các phương pháp tĩnh - họ sẽ không bao giờ có quyền truy cập vào thông tin loại cá thể của một cá thể.)

0

Thực ra đây không phải là vấn đề Java. Thành ngữ đang vượt qua lớp

public static <T extends A<T>> T process(Class<T> clazz) 
    { 
     T o = clazz.newInstance(); 
     process(o); 
     return o; 
    } 

    X x = process(X.class); // not too verbose 

Tôi đã thêm giá trị trả lại để minh họa cho trường hợp chung.

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