这是我的代码:
public class A {
int size = 100;
public int getSize() {
return size;
}
interface D {
}
class B implements D {
}
class C {
int size = 999;
public int getSize() {
return size;
}
}
public void test() {
D d = new B();
System.out.println(((C) d).getSize());
}
public static void main(String[] args) {
A a = new A();
a.test();
}
}
代码编译时没有任何编译器错误。为什么它不会有编译错误呢。类C与引用类型类D和实际的类类型B没有任何关系。它是如何通过类型转换的编译器检查的?
这是我的人性化解释,请参阅@Compass answer以了解规范的详细信息。。
原因是,您是从一个接口进行强制转换的,在这个接口中,它所持有的实例的实际类可能与您要强制转换的类相匹配d
可以容纳类型C
的实例。
只有变量类型对编译时重要,而实例的实际类型对运行时重要。
有关示例,请参阅此代码:
class B { ... }
class C { ... }
interface D { ... }
// only variable type matters for compile-time
// the compiler (usually?) doesn't care what's in them
D d = ...;
B b = ...;
// compile error
// `b` can't contain an instance inheriting from `C`.
C c2 = (C) b;
// no compile error
// `d` might contain an instance inheriting from `C`.
C c1 = (C) d;
// it's because of the possibility like below
// that the compiler doesn't complain.
class E extends C implements D { ... }
D d = new E();
C c = (C) d;
来自JLS 5.5.1,参考类型铸造:https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.5.1
给定编译时引用类型S(源)和编译时引用类型T(目标),如果没有由于以下规则而发生编译时错误,则存在从S到T的转换。
在我们的例子中,S=D(接口),T=C(类)。
如果S是类类型:
S是一个接口,所以我们跳过这个。
如果S是接口类型:
D是一个接口,所以我们使用这个分支。
如果T是数组类型,那么S必须是java类型。伊奥。Serializable或Cloneable(由数组实现的唯一接口),或发生编译时错误。
T不是数组类型,我们跳过它。
如果T是一个不是最终的类或接口类型(§8.1.1),那么如果存在T的超类型X和S的超类型Y,使得X和Y都是可证明的不同参数化类型,并且X和Y的擦除是相同的,则会发生编译时错误。
我们没有这个。我们当然可以创建一个来实现这一点,但这需要重新定义C以适应这个模型。
否则,强制转换在编译时总是合法的(因为即使T不实现S,T的子类也可能实现)。
换句话说,编译器没有理由抛出错误,因为很可能在其他地方存在一个可用于限定强制转换的可能类。
例如,你可以在其他地方看到:
class E extends C implements D { ... }
终结C会导致编译时错误:
final class C { ... }
基本上,存在一种可能性,即存在一种在运行时工作的C实现,这种实现在编译时无法验证。
问题内容: 我得到这个错误 01-14 12:20:57.591:E / AndroidRuntime(1825):原因:android.content.res.Resources $ NotFoundException:字符串资源ID#0x7f040003 如果我使用类变量保存上下文并执行 context.getString(R.string.create_profile_table_sql)*
问题内容: 在我的关于多态性的专业幻灯片中,我看到了这段代码,并带有一些注释: 如您所见,它在第一个强制转换语句中表示将产生 运行时 错误,而在另一个声明中将产生 编译器错误 。 是什么导致这些错误?以及它们之间有何不同? 问题答案: 仅在代码实际运行时才会发生运行时错误。这些是最困难的-导致程序崩溃和代码中的错误,难以跟踪。 一个示例可能正在尝试将字符串“ hello”转换为整数: 编译器可能不
想知道这里可能发生了什么,以及如何解决这个错误?它不像taglibs库版本出现在mvnrepository站点上那样出现,所以我想知道该怎么办? 提前谢了。
问题内容: 我一直在尝试创建一个新项目以使用UCanAccess读取MS Access文件。我一直在关注@Gord Thompson的信息以及github中的UCanAccess示例文件。除了我使用不同名称的事实外,每件事都是相同的。我不使用任何GUI IDE。我只是从命令行进行编译,基本上,我编写了一个执行命令行编译的Java程序。 参考文献: 在不使用ODBC的情况下从Java操作Access
问题内容: 下面的代码可以快速编译和运行。 我希望这是一个编译错误,因为结构永远不能符合AnyObject。如以下通过无法编译的代码所示。 我知道某些类型(例如String)可能会发生桥接。这将转换引用类型的值类型。 在写这个问题时,我想知道投射对象的类型是什么,似乎它也以某种方式被桥接。 为什么允许这种类型的铸造?似乎期望引用类型的函数违反了约定。 在重构一些代码以支持值类型时,我偶然发现了这一
我的意思是,我理解这个错误,但是我在AndroidLollipop和Marshmallow上没有看到错误,只有在奇巧上。 我通过意图将一个生物维数组从一个活动发送到另一个活动,如下所示: 在接收活动中,我正在这样做: 同样,这在Android 5和6上运行得很好,但在Android 4上却出现了错误。 从Lollipop开始的系列化发生了什么变化?