是对象数组的字符串数组子类



我想我在这里缺少一些基本的东西。任何解释或指向先前提出的问题的指针都将非常有帮助。

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[]的子类。

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

谢谢

Java 数组是协变的,即它们允许Object[] foo = new String[2]; .但这并不意味着它们是子类。 String[]Object 的子类(尽管instanceof返回 true,String[].class.getSuperclass()返回 Object (

是的,你的假设是有效的。如@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(也不是其子类型(:Date

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

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

String[]

是 Object[] 的子类

正确,请参阅 4.10.3 数组类型之间的子类型:

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

既然String >1 Object这么String[] >1 Object[]

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

对象>1 对象[]

因此Object > String[]; String[]是(间接的?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正在使用不是List<I>List<C>调用allF。为了能够使用List<C>签名必须稍作更改:

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

现在它编译了。非正式地说,li是扩展/实现 I 的某种类型的List。所以List<C>可以分配给List<? extends I>.您可以使用此类列表执行的操作是有限的。本质上,您可以读取/访问它,但不能write/modify它。

最新更新