2012-09-11 28 views
30
Object[] o = "a;b;c".split(";"); 
o[0] = 42; 

némĐối phó với một ArrayStoreException

java.lang.ArrayStoreException: java.lang.Integer 

khi

String[] s = "a;b;c".split(";"); 
Object[] o = new Object[s.length]; 
for (int i = 0; i < s.length; i++) { 
    o[i] = s[i]; 
} 
o[0] = 42; 

không.

Có cách nào khác để giải quyết ngoại lệ đó mà không tạo mảng String[] tạm thời không?

+4

Đối tượng [] o = "a; b; c" .split (";"); o [0] = 42; ở đây bạn đang tạo một mảng Strings, trong khi Object [] o = new Object [s.length]; là một mảng các đối tượng. – Satya

Trả lời

53

Trong Java, mảng cũng là đối tượng .

Bạn có thể đặt đối tượng loại phụ vào biến số supertype. Ví dụ: bạn có thể đặt đối tượng String vào biến số Object.

Thật không may, định nghĩa mảng trong Java bằng cách nào đó bị hỏng. String[] được coi là loại phụ của Object[], nhưng đó là sai! Đối với một lời giải thích chi tiết hơn đọc về "hiệp phương sai và contravariance", nhưng bản chất nó này: Một loại nên được coi là một loại phụ của loại khác chỉ khi các loại phụ đáp ứng tất cả các nghĩa vụ của siêu loại. Điều đó có nghĩa, rằng nếu bạn nhận được một đối tượng subtype thay vì một đối tượng supertype, bạn không nên mong đợi hành vi mâu thuẫn với hợp đồng supertype.

Vấn đề là String[] chỉ hỗ trợ một hợp đồng một phần của Object[]. Ví dụ: bạn có thể đọcObject giá trị từ Object[]. Và bạn cũng có thể đọcObject giá trị (xảy ra là String đối tượng) từ String[]. Càng xa càng tốt. Vấn đề là với phần khác của hợp đồng. Bạn có thể đặt bất kỳObject vào Object[]. Nhưng bạn không thể đặt bất kỳObject vào String[]. Do đó, String[] không nên được coi là loại phụ của Object[], nhưng đặc điểm kỹ thuật Java cho biết. Và do đó chúng tôi có những hậu quả như thế này.

(Lưu ý rằng một tình huống tương tự đã xuất hiện một lần nữa với các lớp học chung, nhưng lần này nó đã được giải quyết đúngList<String>không một subtype của List<Object>;. Và nếu bạn muốn có một supertype phổ biến cho các bạn cần List<?>, chỉ đọc.Đây là cách nó cũng nên được với mảng; nhưng không phải vậy. Và vì khả năng tương thích ngược, đã quá muộn để thay đổi nó.)

Trong ví dụ đầu tiên của bạn, hàm String.split tạo đối tượng String[]. Bạn có thể đặt nó vào biến số Object[] nhưng đối tượng vẫn là String[]. Đây là lý do tại sao từ chối giá trị Integer. Bạn phải tạo một mảng Objects[] mới và sao chép các giá trị. Bạn có thể sử dụng hàm System.arraycopy để sao chép dữ liệu, nhưng bạn không thể tránh tạo mảng mới.

+0

http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ102 –

6

Không, không có cách nào để tránh sao chép mảng mà split trả về.

Mảng trả về split thực sự là một String[] và Java cho phép bạn gán giá trị đó cho biến số Object[]. Nó vẫn thực sự là một String[] tuy nhiên, vì vậy khi bạn cố gắng lưu trữ một cái gì đó khác hơn là String trong đó, bạn sẽ nhận được một ArrayStoreException.

Để biết thông tin cơ bản, hãy xem 4.10.3. Subtyping among Array Types trong Đặc tả ngôn ngữ Java.

0

Có tất nhiên các tùy chọn khác, giống như bạn triển khai phương thức tách riêng của bạn, phương thức này trả về một mảng Đối tượng trực tiếp. Tôi không chắc chắn mặc dù những gì thực sự phiền bạn với mảng String tạm thời?

BTW, bạn có thể rút ngắn mã của bạn với một vài dòng sử dụng System.arraycopy thay vì thực hiện vòng lặp của riêng bạn để sao chép các phần tử mảng:

System.arrayCopy(s, 0, o, 0, s.length); 
-1

Nếu nó không phải là cần thiết để sử dụng một "chia tay" .. Sau đó, bạn có thể tránh sao chép ...

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