编译程序时,为什么在标有// 1的行上没有错误,但运行时有一个错误。我是Java的新手,所以我试着更好地理解类的工作方式。
class A{
private int x;
}
class B extends A{
private int a;
void exec(){
System.out.println("test");
}
static void function(A a){
((B)a).exec();//1
}
public static void main(String argv[]){
B.function(new A());
B.function(new B());
}
}
答案 0 :(得分:0)
你说你在运行应用程序时遇到错误,我猜这个案例中的错误是ClassCastException
,因为A
不是B
请注意,这是一个运行时异常:
请参阅:https://docs.oracle.com/javase/7/docs/api/java/lang/ClassCastException.html
详细了解Checked和UnChecked Exceptions:
https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html
http://beginnersbook.com/2013/04/java-checked-unchecked-exceptions-with-examples/
答案 1 :(得分:0)
问题在于每B
个A
(因为B
扩展A
),但反之则不然:并非每个A
都是B
一个A
。因此,有时候,您可能能够像上面的代码中那样将B
投射到BufferedReader
。但是,当存在明显的强制转换时,编译器可以识别问题。例如,考虑尝试将Integer
转换为Integer
的情况:由于BufferedReader
不在ClassCastException
的类层次结构中,因此转换将失败并显示错误:
无法从舞台转换为整数
仅在运行时收到异常的原因是RuntimeException
是RuntimeException
。扩展Exception
的任何异常在编译时都不会被检查。来自Exception
的JavaDoc:
类
RuntimeException
和任何不属于{{1}}子类的子类都是经过检查的异常。如果可以通过执行方法或构造函数抛出并在方法或构造函数边界外传播,则需要在方法或构造函数的throws子句中声明已检查的异常。
答案 2 :(得分:0)
基本上,Java允许您将引用类型转换为另一个引用类型,如果转换可能成功,即它可能不会抛出ClassCastException
。当然,它无法保证它会成功,因为正如您所见,对A
的引用可能是指B
个对象,但它可能不是{{1}对象。
Section 5.5.1 of the JLS详细说明了如果原始引用类型(S)和转换类型(T)都是类类型,导致编译器错误的原因:
给定编译时引用类型S(源)和编译时引用类型T(目标),如果由于以下规则而没有发生编译时错误,则从S到T存在转换转换。
如果S是班级类型:
- 如果T是类类型,则为| S | &lt ;: | T |,或| T | <:| S |。否则,将发生编译时错误。
(JLS中的符号B
表示“是”的子类型。)
由于<:
是B
的子类型,因此您A
到A
的投射是合法的,因为它有可能成功。相反,铸造成不相关的类型,例如B
,将生成编译错误;演员阵容不能成功。