2011-10-18 37 views
31

tôi đang chơi với Generic và mảng, có vẻ như đoạn mã sau biên dịch tốt,Array của Generic Danh sách

ArrayList<Key> a = new ArrayList<Key>(); 

Nhưng trình biên dịch phàn nàn về việc này,

ArrayList<Key>[] a = new ArrayList<Key>[10]; 

Bằng cách đọc bài trong stackoverflow , Tôi hiểu rằng điều này là do Loại xóa và tôi có thể sửa lỗi bằng cách sử dụng,

ArrayList<Key>[] a = (ArrayList<Key> []) new ArrayList[10]; 

hoặc danh sách liệt kê

ArrayList<ArrayList<Key>> b = new ArrayList<ArrayList<Key>>(); 

Nhưng tôi không thể tìm ra lý do đằng sau hiện trường. Đặc biệt, tại sao thứ hai là bất hợp pháp vì cái đầu tiên là hoàn toàn OK. Và tại sao trình biên dịch không phàn nàn về danh sách danh sách.

+3

http://stackoverflow.com/questions/217065/cannot-create-an-array-of-linkedlists-in-java – tcb

Trả lời

22

Bạn không thể có mảng vì mảng yêu cầu loại thô. Bạn đã định kiểu nó trong thể hiện thứ hai, nó làm cho nó phù hợp với loại được xác định, và do đó là hợp pháp (tuy nhiên, điều này là không thể cho nó suy ra). Danh sách danh sách hợp pháp là ArrayList không phải là một mảng.

Đọc chương 7.3 (trang 15) trong official tutorial để biết thêm chi tiết về điều này.

Loại thành phần của một đối tượng mảng có thể không phải là một loại biến hoặc một loại tham số , trừ khi nó là một (không giới hạn) wildcard type.You thể loại mảng khai báo mà kiểu phần tử là một loại biến hoặc một loại tham số, nhưng không phải là đối tượng mảng. Điều này gây phiền nhiễu, để chắc chắn. Hạn chế này là cần thiết để tránh những tình huống như:

List<String>[] lsa = new List<String>[10]; // not really allowed 
Object o = lsa; 
Object[] oa = (Object[]) o; 
List<Integer> li = new ArrayList<Integer>(); 
li.add(new Integer(3)); 
oa[1] = li; // unsound, but passes run time store check 
String s = lsa[1].get(0); // run-time error - ClassCastException 

Nếu mảng của kiểu tham số được phép, ví dụ trên sẽ biên dịch mà không cần bất kỳ cảnh báo không được kiểm soát, nhưng thất bại tại thời gian chạy.

Các hướng dẫn sau đó tiếp tục nói như sau:

Kể từ biến loại không tồn tại thời gian chạy, không có cách nào để xác định những gì thực tế kiểu mảng sẽ. Cách để làm việc xung quanh các loại hạn chế là sử dụng literals lớp như chạy thời gian loại thẻ

1

Các mảng cho phép để thoát kiểm tra kiểu (như minh họa trong câu trả lời của Chris). Vì vậy, bạn có thể có một mã mà vượt qua tất cả các kiểm tra trình biên dịch (không có "không được kiểm soát" cảnh báo từ trình biên dịch), nhưng không thành công tại thời gian chạy với ClassCastException. Ngăn chặn việc xây dựng này làm tăng vấn đề cho nhà phát triển, vì vậy cảnh báo sẽ xuất hiện.

4

Tôi đã tự mình có một số similar question - FWIW, tôi không tìm thấy câu trả lời thuyết phục. Phần thích hợp từ các câu trả lời chi tiết nhất (đề cập đến các tài liệu tham khảo pdf) là thế này:

Loại thành phần của một đối tượng mảng có thể không phải là một loại biến hoặc một loại tham số , trừ khi nó là một (không giới hạn) loại ký tự đại diện.Bạn có thể khai báo các loại mảng có loại phần tử là biến kiểu hoặc loại tham số , nhưng không phải là đối tượng mảng. Điều này gây phiền toái, phải là . Hạn chế này là cần thiết để tránh những tình huống như

 List<String>[] lsa = new List<String>[10]; // not really allowed 
     Object o = lsa; 
     Object[] oa = (Object[]) o; 
     List<Integer> li = new ArrayList<Integer>(); 
     li.add(new Integer(3)); 
     oa[1] = li; // unsound, but passes run time store check 
     String s = lsa[1].get(0); // run-time error - ClassCastException 

Vì vậy, bởi vì tôi có thể mèo Danh mục [] để Object [], sau đó xô một cái gì đó không chính xác vào các Object [], sau đó đề cập đến sai khỏi danh sách tài liệu tham khảo, thông qua các ref đúc, điều này là xấu/không được phép? Nhưng chỉ với mới?

Nó vẫn còn hơi mơ hồ đối với tôi cách khai báo điều này với mới là vấn đề gì nhiều hơn mức sử dụng, nhưng vẫn nhìn vào nó với hy vọng rằng nó sẽ bắt đầu có ý nghĩa, hoặc tại ít nhất là giải quyết thành một hình ảnh 3d đẹp.

+0

biên dịch cần đảm bảo an toàn loại chung; khi không thể, nó phải không cho phép mã hoặc đưa ra cảnh báo. trong ví dụ, một cảnh báo ở dòng thứ 2 có vẻ đủ; quyết định của java để hoàn toàn không cho phép tạo mảng chung dường như quá khắc nghiệt. – irreputable

+1

Có 'ArrayList [] a = (ArrayList []) new ArrayList [10]; 'vẫn còn có cùng một vấn đề, nhưng nó làm cho nó rõ ràng hơn rằng bạn đang gian lận hệ thống kiểu (và nó tạo ra một cảnh báo.) – finnw

+0

finnw, bình luận của bạn là tôi nghĩ câu trả lời đúng và cách duy nhất này có ý nghĩa với tôi. –

2

Tạo mảng chung không an toàn kiểu (xem "Mục 25: Ưu tiên danh sách cho mảng" của "Hiệu quả Java - ấn bản thứ hai" của Joshua Bloch).

Sử dụng:

List<List<Key>> b = new ArrayList<List<Key>>(10); 

Hoặc với Java SE 7:

List<List<Key>> b = new ArrayList<>(10); 
4

Mảng là Generics nghèo của con người; với generics thực, người ta nên tránh mảng, mặc dù không phải luôn luôn có thể.

Mảng là biến thể, generics là bất biến; kết hợp với tẩy xoá, mọi thứ không phù hợp lắm, như minh họa bằng ví dụ trong câu trả lời của Chris.

Tuy nhiên tôi nghĩ rằng có thể thư giãn thông số để cho phép tạo mảng chung - thực sự không có vấn đề gì ở đó. Nguy hiểm xuất hiện khi lên mảng; một cảnh báo trình biên dịch tại thời điểm đó là đủ.

Trên thực tế Java không tạo mảng chung cho các phương pháp vararg, do đó, nó có một chút đạo đức giả.

Dưới đây là phương pháp hữu ích lợi dụng thực tế là

@SafeVarargs 
static <E> E[] arrayLiteral(E... array) 
{ 
    return array; 
} 

@SafeVarargs 
static <E> E[] newArray(int length, E... array) 
{ 
    return Arrays.copyOf(array, length); 
} 

// usage 

    List<String>[] array1 = arrayLiteral(list, list); 

    List<String>[] array2 = newArray(10); 
+0

Có thể do khả năng tương thích ngược. Giả sử một số phiên bản tương lai (Java 9?) Cho phép tạo mảng chung, sau đó khi mã Java 9 trộn với mã Java 5/6/7/8 (có thể upcast mảng không có cảnh báo) kết quả sẽ là ClassCastExceptions không mong đợi. – finnw

+0

Điều này không hoạt động nếu 'E' là một biến kiểu. Các varargs tạo ra một mảng xóa của 'E' khi' E' là một biến kiểu, làm cho nó không khác nhiều so với '(E []) đối tượng mới [n]'. Vui lòng xem [http://ideone.com/T8xF91] (http://ideone.com/T8xF91). – Radiodef

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