2009-07-02 30 views
23

Tôi bắt gặp một cái gì đó rất cơ bản nhưng cực kỳ hoang mang ngày nay. Tôi cần chuyển đổi một danh sách thành một mảng. Danh sách chứa String trường hợp. Ví dụ hoàn hảo về việc sử dụng List.toArray(T[]), vì tôi muốn một phiên bản String[]. Nó sẽ không hoạt động, tuy nhiên, mà không rõ ràng đúc kết quả đến String[].Hành vi generics Odd của List.toArray (T [])

Như một kịch bản thử nghiệm, tôi đã sử dụng đoạn mã sau:

import java.util.Arrays; 
import java.util.List; 

public class MainClass { 
    public static void main(String args[]) { 
     List l = Arrays.asList("a", "b", "c"); 
     String stuff[] = l.toArray(new String[0]); 
     System.err.println(Arrays.asList(stuff)); 
    } 
} 

mà không biên dịch. Đó là gần một bản sao chính xác của ví dụ trong javadoc, nhưng trình biên dịch cho biết như sau:

MainClass.java:7: incompatible types 
found : java.lang.Object[] 
required: java.lang.String[] 
    String stuff[] = l.toArray(new String[0]); 
         ^

Nếu tôi thêm một dàn diễn viên để String[] nó sẽ biên dịch và chạy một cách hoàn hảo. Nhưng đó không phải là những gì tôi mong đợi khi tôi nhìn vào chữ ký của phương pháp toArray:

<T> T[] toArray(T[] a) 

Điều này nói với tôi rằng tôi không nên bỏ. Chuyện gì vậy?

Edit:

Tò mò, nếu tôi thay đổi việc kê khai danh sách công việc:

List<?> l = Arrays.asList("a", "b", "c"); 

nó cũng làm việc. Hoặc List<Object>. Vì vậy, nó không phải là một List<String> như đã được đề xuất. Tôi bắt đầu nghĩ rằng việc sử dụng kiểu thô List cũng thay đổi cách các phương thức chung trong lớp đó hoạt động.

Chỉnh sửa thứ hai:

Tôi nghĩ mình đã hiểu ngay bây giờ. Những gì Tom Hawtin đã viết trong một bình luận dưới đây có vẻ là giải thích tốt nhất. Nếu bạn sử dụng một kiểu generic theo cách thô, tất cả các thông tin generics từ cá thể đó sẽ bị xóa bởi trình biên dịch.

Trả lời

29

bạn quên để xác định các tham số kiểu cho Danh sách của bạn:

List<String> l = Arrays.asList("a", "b", "c"); 

trong trường hợp này bạn có thể viết an toàn:

String[] a = l.toArray(new String[0]); 

mà không cần bất kỳ diễn viên.

+1

Điều này có ý nghĩa đối với tôi một cách hợp lý, nhưng không phải về mặt kỹ thuật. Nó không nhìn vào tôi rằng phương thức toArray quan tâm đến những gì E bị ràng buộc (tức là, lớp phần tử của danh sách). – waxwing

+1

chữ ký của toArray là "công khai T [] toArray (T [] a)", T là loại thành phần của mảng được truyền trong – dfa

+0

Tôi cũng không thể hiểu nó, tệ hơn là nó cũng hoạt động bằng cách sử dụng Danh sách (hoặc Danh sách ) cho "l" –

1
List<String> l = Arrays.asList("a", "b", "c"); 

điều này sẽ biên dịch, bạn đang sử dụng generics để nói "đây là danh sách các chuỗi" để phương thức toArray biết loại mảng nào cần trả về.

0

Đó là vì danh sách của bạn chứa các đối tượng chứ không phải các chuỗi. Nếu bạn đã khai báo danh sách của mình là List<String>, trình biên dịch sẽ rất vui.

3

hoặc làm

List<?> l = Arrays.asList("a", "b", "c"); 

vẫn lạ

+0

+1 để truy cập. Nó giải quyết được vấn đề - tôi nhận thấy sự kỳ quặc giống như bản thân mình. – waxwing

+1

tồi tệ nhất: nó cũng biên dịch bằng cách sử dụng Danh sách nhưng sẽ bị lỗi khi chạy ...: - / –

0

List mà không có một loại tuyên bố sẽ mặc định "Danh sách đối tượng" trong khi List<?> có nghĩa là "List of unknown".Trong thế giới của các kiểu generic, thực tế là "List of Object" khác với "List of String" nhưng trình biên dịch không thể nói tương tự cho "List of unknown". Nếu bạn đã tuyên bố nó là chưa biết thì, theo như trình biên dịch có thể nói, thì đó là OK.

Điểm chính là tuyên bố thứ gì đó làm ký tự đại diện? khác với tuyên bố nó là Object. Đọc thêm về các ký tự đại diện here

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