Java泛型接口转换

20

我偶然发现了一个涉及Java泛型和接口的强制类型转换问题,但我并不理解。

请看下面的代码,我创建了一个List<Interface1>,然后使用get()方法获取一个元素,并将其强制转换为Interface2,尽管这两个接口完全没有关系,却没有编译错误。

import java.util.*;

public class Main {
  public static void main(String ... args) {
    List<Interface1> list = new ArrayList<>();
    list.add(new Interface1() {});

    Interface1 ok = list.get(0);
    Interface2 why = (Interface2)list.get(0);
  }
}

interface Interface1 {
}

interface Interface2 {
}

有人可以解释一下为什么第二个get(0)的强制转换没有编译错误吗?

顺便说一下:执行该类会抛出ClassCastException异常(如预期所示)。而使用两个类而不是接口实际上会产生编译错误。

6个回答

29

这种行为与泛型无关:您可以将任何接口转换为任何其他接口而不会出现编译错误。

但是,您无法对类执行此操作,因为Java可以在编译时检查一个类是否可以转换为另一个类。

然而,对于接口,类型转换可能成功也可能失败,这取决于实际实现接口的类。尽管如此,只有在运行时才能发现这一点。


8
如果您有一个实现了Interface1接口的类型,那么它也可以实现Interface2接口。因此,在运行时转换可能会成功,编译器不会责怪您。

4

有可能Interface1的子类也是Interface2的子类,因此编译不会出错。


4
这是因为JAVA支持多接口实现。由于我们可以有任意数量的类,任何类型(任何父类)可以实现一个接口,JVM设计使得在运行时之前无法确定传递给接口的类型。因此,ArrayList中可以放置任何接口。

4
编译器不知道这样做不起作用:您可能会拥有类型为Interface2的实例,该实例也是Interface1类型(例如:class ImplementingClass implements Interface1、Interface2)。然后转换将是正确的。
“使用两个类而不是接口确实会生成编译错误。”
在这种情况下,编译器知道它行不通,因此您在这种情况下会得到编译错误。

2

这不是通用问题。JVM对于Interface1Interface2之间的兼容性没有“认知”,所以你会得到ClassCastException


如果一个对象同时实现了两个接口,则会出现错误。 - Silviu Burcea
@SilviuBurcea 这里的 Interface1Interface2 是两个不同的接口。 - Michael Kazarian
1
Silviu的观点是,Interface1和Interface2是不同的接口,并不意味着一个实例化对象不能同时实现两个接口。由于编译器无法知道这一点,它将允许强制转换。ClassCastException发生是因为匿名类没有实现Interface2。 - Taemyr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接