Đây là cách sử dụng thuốc generic để có được một mảng chính xác loại bạn đang tìm kiếm trong khi bảo vệ an toàn loại (trái ngược với các câu trả lời khác, sẽ cung cấp cho bạn một Objectmảng hoặc dẫn đến cảnh báo tại thời điểm biên dịch):
import java.lang.reflect.Array;
public class GenSet<E> {
private E[] a;
public GenSet(Class<E[]> clazz, int length) {
a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));
}
public static void main(String[] args) {
GenSet<String> foo = new GenSet<String>(String[].class, 1);
String[] bar = foo.a;
foo.a[0] = "xyzzy";
String baz = foo.a[0];
}
}
Nó biên dịch mà không có cảnh báo, và như bạn có thể thấy main, đối với bất kỳ loại nào bạn khai báo một thể hiện GenSetnhư, bạn có thể gán acho một mảng của loại đó và bạn có thể gán một phần tử từ amột biến của loại đó, nghĩa là mảng đó và các giá trị trong mảng là đúng loại.
Nó hoạt động bằng cách sử dụng các chữ theo lớp làm mã thông báo loại thời gian chạy, như được thảo luận trong Hướng dẫn Java . Lớp chữ được trình biên dịch coi là phiên bản của java.lang.Class. Để sử dụng một, chỉ cần làm theo tên của một lớp với .class. Vì vậy, String.classhoạt động như một Classđối tượng đại diện cho lớp String. Điều này cũng hoạt động cho các giao diện, enums, mảng bất kỳ chiều (ví dụ String[].class), nguyên thủy (ví dụ int.class) và từ khóa void(ví dụ void.class).
Classchính nó là chung (khai báo là Class<T>, nơi Tđứng cho các loại hình mà Classđối tượng là đại diện cho), có nghĩa là các loại String.classlà Class<String>.
Vì vậy, bất cứ khi nào bạn gọi các nhà xây dựng cho GenSet, bạn vượt qua trong một chữ lớp cho đối số đầu tiên đại diện cho một mảng của GenSetkiểu được khai báo của ví dụ (ví dụ như String[].classcho GenSet<String>). Lưu ý rằng bạn sẽ không thể có được một loạt các nguyên hàm, vì các nguyên thủy không thể được sử dụng cho các biến loại.
Bên trong hàm tạo, việc gọi phương thức casttrả về Objectđối số đã truyền cho lớp được đại diện bởi Classđối tượng mà phương thức được gọi. Gọi phương thức tĩnh newInstancetrong java.lang.reflect.Arraylợi nhuận như một Objectmột mảng của các loại đại diện bởi các Classđối tượng thông qua như là đối số đầu tiên và chiều dài theo quy định của intthông qua như là đối số thứ hai. Gọi phương thức getComponentTypetrả về một Classđối tượng đại diện cho các loại thành phần của mảng đại diện bởi các Classđối tượng trên mà phương pháp này được gọi là (ví dụ như String.classcho String[].class, nullnếu Classđối tượng không đại diện cho một mảng).
Câu cuối cùng không hoàn toàn chính xác. Gọi String[].class.getComponentType()trả về một Classđối tượng đại diện cho lớp String, nhưng kiểu của nó Class<?>thì không Class<String>, đó là lý do tại sao bạn không thể làm một cái gì đó như sau.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
Tương tự với mọi phương thức trong Classđó trả về một Classđối tượng.
Về nhận xét của Joachimerer về câu trả lời này (tôi không đủ uy tín để tự nhận xét về nó), ví dụ sử dụng diễn viên T[]sẽ dẫn đến cảnh báo vì trình biên dịch không thể đảm bảo an toàn loại trong trường hợp đó.
Chỉnh sửa liên quan đến ý kiến của Ingo:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}