是Object数组的String数组子类吗?

时间:2012-01-11 19:29:29

标签: java arrays collections

我想我错过了一些基本的东西。对先前提出的问题的任何解释或指示将非常有用。

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
    }

}

因此,似乎List<String>不是List<Object>的子类,而String[]Object[]的子类。

这是一个有效的假设吗?如果是这样,为什么?如果没有,为什么?

由于

5 个答案:

答案 0 :(得分:10)

Java arrays are covariant,即他们允许Object[] foo = new String[2];。但这并不意味着它们是子类。 String[]Object的子类(虽然instanceof返回true,String[].class.getSuperclass()返回Object

答案 1 :(得分:5)

是的,您的假设是有效的。正如@Bozho所说,数组是协变的,而泛型集合(如泛型List)则不是协变的。

数组中的协方差存在风险:

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 

第三行触发运行时异常。如果它没有触发此异常,那么您可以获得String变量s,该变量引用的值不是String(也不是其子类型):a {{1 }}

答案 2 :(得分:3)

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

答案 3 :(得分:3)

你是对的。数组类型在Java中是协变的,但是Foo<Sub>不是Foo<Super>

答案 4 :(得分:2)

  

String []是Object []

的子类

正确,请参阅4.10.3 Subtyping among Array Types

  

如果S和T都是参考类型,则S []> 1 T [] iff S> 1 T。

String >1 Object以来String[] >1 Object[]

也就是说,String[]Object[]直接子类型

  

对象&gt; 1对象[]

因此Object > String[]; String[]是({1}}

的(间接?)子类型

泛型不存在这种关系,因此Object不正确。

现在,请考虑以下简单示例:

List<String>  > List<Object>

它无法编译,因为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); } } 正在使用x来调用allF <{1>} <{1}}。为了能够使用List<C>,签名必须略有改变:

List<I>

现在它编译。非正式地,List<C>某种类型的void allF(List<? extends I> li) { ,可以扩展/实现I.因此li 可分配给 {{1} }。你可以用这样的清单做什么是有限的。基本上,您可以读取/访问它但不能List它。