Java 为什么可以创建一个新的接口数组

Java 为什么可以创建一个新的接口数组,java,arrays,interface,casting,Java,Arrays,Interface,Casting,为什么在Java中可以执行以下操作 Integer[] ints = (Integer[])new Comparable[10]; 但它在运行时得到ClassCastException。new接口数组的用例是什么。考虑这种情况:您有一个接口和两个(或更多)类来实现该接口: interface MyInterface { public void someMethod(); } class MyClass1 implements MyInterface { public void

为什么在Java中可以执行以下操作

Integer[] ints = (Integer[])new Comparable[10];

但它在运行时得到
ClassCastException
new
接口数组的用例是什么。

考虑这种情况:您有一个接口和两个(或更多)类来实现该接口:

interface MyInterface
{
    public void someMethod();
}

class MyClass1 implements MyInterface
{
    public void someMethod() { System.out.println("foo");}
}

class MyClass2 implements MyInterface
{
    public void someMethod() { System.out.println("bar");}
}
public final class Integer extends Number implements Comparable<Integer>
你这样称呼它:

public static void main(String[] args)
{
    MyInterface[] array = new MyInterface[2];
    array[0] = new MyClass1();
    array[1] = new MyClass2();

    array[0].someMethod();
    array[1].someMethod();
}

接口数组提供了将该接口的不同实现保存在数组中的方法来回答特定问题:

Comparable toComplare[] = new Comparable[10];
为什么不创建一个数组来存储实现可比较接口的任何对象

要点是:界面表示一种“通用功能”-仅从该“视图”查看对象可能会有所帮助

当然,存储在该数组中的对象始终属于某种“真实”类,但所有这些对象都将实现
Compariable
接口提供的功能

所以你可以这样做:

toCompare[0] = new Integer(5);
toCompare[1] = new BigDecimal("3.2");
...
我并不是说这是您经常使用的东西,但正如所说的,它允许您在特定的特定“视图”下“收集”对象的功能。还值得指出的是:拥有这样一个数组并不意味着你能够:

toCompare[0].compareTo(toCompare[1]);
成功


除此之外:cast总是暗示程序员知道一些编译器不知道的事情。因此,编译器会退一步让您这样做——假设您知道自己在做什么。但是,由于您在问题中显示的代码显然是不正确的,所以在运行时,现实又回来了。是的,在编译时可以判定给定的代码是错误的

拥有
整数
实现
可比
,并不意味着
整数[]
实现
可比[]
,因此不能转换不同类型的数组。但是,您可以将
整数
放在
可比[]
数组的元素中。

编译器查看右侧的类型,发现它是一个
可比
数组。一般来说,它可以是一个
整数[]
(因为它可分配给
可比[]

我们知道它不会是一个
整数[]
,因为右边的表达式是一个构造函数调用。但是编译器看起来并没有那么远。它使用相同的逻辑,就好像该表达式是一个方法调用,其声明类型为
Comparable[]
。它不会查看内部以确定实际类型

因此编译器将接受您的类型转换,因为它可能会成功。它只会拒绝根本无法执行的强制转换(根据声明的类型),例如将
Integer
强制转换为
String

请注意,在阵列中允许这种协方差可能是一个设计缺陷。您可以将
Integer[]
强制转换为
compariable[]
,但这存在问题,因此您无法将
List
强制转换为
List

  • ClassCastException
    的原因是堆污染。 请在此处查找更多详细信息
  • new
    到接口数组/just接口的用例是用实现该接口的任何类对象填充它(或给出匿名内部类定义)

  • 这是因为您正在执行缩小参考转换

    Integer类实现了可比较的接口:

    interface MyInterface
    {
        public void someMethod();
    }
    
    class MyClass1 implements MyInterface
    {
        public void someMethod() { System.out.println("foo");}
    }
    
    class MyClass2 implements MyInterface
    {
        public void someMethod() { System.out.println("bar");}
    }
    
    public final class Integer extends Number implements Comparable<Integer>
    
    public final类整数扩展数字
    
    见:

    从任何数组类型SC[]到任何数组类型TC[],前提是SC和TC是引用类型,并且存在从SC到TC的缩小引用转换

    这种转换需要在运行时进行测试,以确定实际引用值是否是新类型的合法值。如果不是,则抛出ClassCastException


    java在运行时识别类型。强制转换无法隐藏实际类型。
    整数
    是-a
    可比
    ,但
    可比
    不一定是
    整数
    。这不是创建接口实例,而是创建实现接口的类。请解释下一票?我弄错什么了吗?在这种特殊情况下,静态分析器可能也会在编译时标记它。@Thilo Correct;我又加了一句话。编译器在这里没有抱怨这一事实可能是这个问题最有趣的方面。编译器不能按照语言规范拒绝它(但它可能会发出警告,我们已经看到这些年来添加了越来越多的警告)@Thilo你能指出你心目中JLS中的具体部分吗?仍在寻找。目前,相关线程:堆污染不能发生在数组中,因为它们在运行时检查组件类型(不像泛型集合那样被擦除)。如果你试图加入一些不好的东西,你会得到ArrayStoreExceptions。这是错误的。您完全可以将
    整数[]
    分配给
    可比[]
    。这可以很好地编译和运行:
    Comparable[]x=newinteger[10]这与我写的完全相反。试试这个
    Integer[]ints=(Integer[])新的可比[]{1}
    ,您将在线程“main”java.lang.ClassCastException:[Ljava.lang.Comparable;无法转换为[Ljava.lang.Integer;
    中收到
    异常,您编写的“
    整数[]
    未实现
    可比[]
    ”。这是错误的。每个
    整数[]
    也是一个
    可比[]