2012-01-11 37 views
7

Tôi nghĩ rằng tôi đang thiếu một cái gì đó cơ bản ở đây. Bất kỳ lời giải thích hay chỉ dẫn nào cho các câu hỏi trước đây sẽ rất hữu ích.Là một lớp con mảng String của một mảng đối tượng?

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

public class St { 

    public static void bla(Object[] gaga) { 
      gaga[0] = new Date(); // throws ArrayStoreException 
     System.out.println(gaga[0]); 
    } 

    public static void bla(List<Object> gaga) { 
     System.out.println(gaga.get(0)); 
    } 

    public static void main(String[] args) { 
      String[] nana = { "bla" }; 
     bla(nana); // Works fine 

     List<String> bla1 = Arrays.asList(args); 
     bla(bla1); // Wont compile 

      System.out.println(new String[0] instanceof Object[]); // prints true 
      System.out.println(nana.getClass().getSuperclass().getSimpleName()); // prints Object 
    } 

} 

Vì vậy, nó có vẻ như một List<String> không phải là một lớp con của một List<Object> nhưng một String[] là một lớp con của Object[].

Đây có phải là giả định hợp lệ không? Nếu vậy, tại sao? Nếu không, tại sao?

Cảm ơn

Trả lời

10

Java arrays are covariant, tức là họ cho phép Object[] foo = new String[2];. Nhưng điều này không có nghĩa là chúng là các lớp con. String[] là một lớp con của Object (mặc dù instanceof trả về true, String[].class.getSuperclass() lợi nhuận Object)

+0

Từ @maerics bình luận bên dưới - đối tượng 'String mới [0] của Object []' trả về true. Vì vậy, String [] là một loại đối tượng và một loại đối tượng [] và một loại CharSequence [] vv. – Kal

+0

@Kal dường như là một trường hợp đặc biệt để bao gồm hiệp phương sai. Xem cập nhật của tôi – Bozho

+0

Cảm ơn .. Chỉ cần xem bản chỉnh sửa của bạn. – Kal

3
(new String[0] instanceof Object[]) // => true 
3

Bạn là chính xác. Các loại mảng là biến thể trong Java theo thiết kế, nhưng Foo<Sub> không phải là Foo<Super>.

5

Có, giả thiết của bạn là hợp lệ. Như đã nói bởi các mảng @Bozho là covariant, trong khi các bộ sưu tập chung chung (chẳng hạn như Danh sách chung) không phải là biến thể.

Hiệp phương sai trong mảng là rủi ro:

String[] strings = new String[] { "a", "b" } 
Object[] objects = strings; 
objects[0] = new Date(); // <-- Runtime error here 
String s = strings[0]; 
s.substring(5, 3);  // ????!! s is not a String 

Dòng thứ ba bắn một ngoại lệ thời gian chạy. Nếu không kích hoạt ngoại lệ này thì bạn có thể nhận được biến số String, s, tham chiếu đến giá trị không phải là String (cũng không phải loại phụ của chúng): a Date.

+0

Cảm ơn .. Tôi chưa bao giờ thấy ArrayStoreException trước đây. – Kal

2

String [] là một lớp con của Object []

Đúng, xem 4.10.3 Subtyping among Array Types:

Nếu S và T là cả hai loại tài liệu tham khảo, sau đó S []> 1 T [ ] khi và chỉ khi S> 1 T.

Kể từ String >1 Object nên String[] >1 Object[]

Đó là, String[] là một trực tiếp kiểu phụ của Object[]

Object> 1 Object []

Therefor Object > String[]; String[] là một (gián tiếp?) kiểu phụ của Object

Không mối quan hệ như vậy tồn tại cho generics, vì vậy List<String> > List<Object> là không đúng sự thật.

Bây giờ, hãy xem xét các ví dụ đơn giản sau:

import java.util.*; 

class G { 
    interface I { 
    void f(); 
    } 
    class C implements I { 
    public void f() {} 
    } 

    void allF(List<I> li) { 
    for (I i : li) { i.f(); } 
    } 

    void x(List<C> lc) { 
    allF(lc); 
    } 
} 

Nó không biên dịch, vì x được gọi allF với một List<C> đó là không một List<I>. Để có thể sử dụng List<C> chữ ký phải thay đổi một chút:

void allF(List<? extends I> li) { 

Bây giờ nó biên dịch. Không chính thức, liList của một số loại mở rộng/triển khai I. Vì vậy, List<C>được gán choList<? extends I>. Những gì bạn có thể làm với danh sách như vậy bị giới hạn. Về cơ bản, bạn có thể đọc/truy cập nó nhưng không thể write/modify nó.

+0

Umm ... loại phụ và phân lớp có nghĩa là những thứ khác nhau. –

+1

@StephenC, để phân lớp phụ giống như lớp con, nếu tôi đọc [4.10.2] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls- 4.10.2). Tôi đoán câu trả lời đúng sẽ là "Mảng không phải là lớp nên chúng không thể có mối quan hệ lớp con nhưng String [] * là * a * sybtype * của Object []". Đó là những gì bạn đang gợi ý? –

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