使用"界面"进行投射

kev*_*kev 20 java

interface I{}
class A implements I{}
class B{}
Run Code Online (Sandbox Code Playgroud)

第一:

I[] arr = new A[10];
arr[0] = (I) new B(); // will produce ClassCastException at runtime
Run Code Online (Sandbox Code Playgroud)

第二:其中如果我使用具体的课程

I[] arr = new A[10];
arr[0] = (A) new B(); // will produce compile-time error
Run Code Online (Sandbox Code Playgroud)

如果在我的第一个例子中,(I) new B()java编译器也应该产生编译错误,那有什么区别?

是不是java编译器应该能够区分它也是一个"不可转换的类型"?特别是当新的操作员马上到来时?

是否有任何实例/机会可能创建B的新实例可以生成类型I的可转换类型?

我知道在某些时候,Java编译器不应该立即说它是编译器错误,就像你这样做:

I i = (I) getContent(); // wherein getContent() will return a type of Object
Run Code Online (Sandbox Code Playgroud)

编辑:

让我澄清一下这个问题为什么它不可能重复:将已知类型的引用转换为类型层次结构之外的接口

这个问题的目的不是因为我不知道会有什么结果或什么是错的东西等等.

我只是想知道"技术方面更详细的解释",为什么JVM会采用这种方式行事,或者为什么Java想出了那种不使这种情况成为编译时错误的决定.

众所周知,在编译时而不是在运行时找到"有问题的代码"总是更好.

另一件事,我正在寻找的答案是在这个线程上找到的而不是那些"重复?".

use*_*ica 10

什么强制转换是编译时合法的规则只考虑静态类型.

当Java编译器分析的表达(I) new B(),它看到的静态类型表达的new B()B.我们可以告诉它new B()不可能是一个实例I,但是编译时分析规则不能告诉该对象实际上不是B该实现的子类的实例I.

因此,编译器必须让它通过.根据编译器的复杂程度,它可能会检测到奇怪性并发出某种警告,但同样的方式1/0不是编译时错误,这不是编译时错误.


Iva*_*kov 5

这种情况的不同显然I是一个可以实现的接口.这意味着,即使B没有任何关系I,也可能有B实现接口的子类I.将用一个例子来说明这一点:

interface I{}
class A implements I{}
class B{}
class C extends B implements I{}

I[] arr = new A[10]; // valid, cause A implements I
B b = new C(); // Valid because C is a subclass of B
arr[0] = (I) b; // This won't produce ClassCastException at runtime, because b
                // contains an object at runtime, which implements I
arr[0] = (I) new B(); // This will compile but will result in a ClassCastException
                      // at runtime, cause B does not implement I
Run Code Online (Sandbox Code Playgroud)

区分staticdynamic类型之间的区别很重要.在这种情况下,变量的静态类型bB,但它具有动态类型(运行时类型)C,其中new B()也有静态类型B,但动态类型也是B.并且在某些情况下,来自Bto的I强制转换不会导致异常(如本方案中所示),编译器允许这样的强制转换但允许接口类型.

现在来看看以下场景:

I[] arr = new A[10];
B b = new C(); // Valid because C is a subclass of B
A a1 = (A) b; // compile time error
A a2 = (A) new B(); // compile time error
Run Code Online (Sandbox Code Playgroud)

有没有可能是子类B都不会延长A,并B在同一时间?答案是否定的,因为你只限于一个超类来扩展Java(在其他一些OO语言中并非如此),因此编译器禁止它,因为没有可能的情况,这将起作用.