public class Test1 {
int a;
int b;
}
public class Test2 extends Test1 {
public int c;
Test2(int a,int b,int c){
this.a=a;
this.b=b;
this.c=c;}
}
public class Driver {
public static void main(String[] args) {
Test2 test1 = new Test2(3,4,5);
Test1 test = new Test1();
test=test1; //This line is true
test1=test; //This line is false
}
}
即使我看了书中的例子,我也听不懂。怎么可能?为什么在“test1 = test”行遇到编译错误?有人可以解释一下吗?
答案 0 :(得分:2)
赋值转换的规则(在将表达式的值赋给变量时会发生这种情况)在section 5.2 of the Java Language Specification中详细说明。特别是,将引用类型分配给更宽的引用变量始终是合法的:
如果 S 是 S 的子类型(§4.10) Ť
在您的情况下,由于test
的引用类型为Test1
,因此分配Test1
类型的任何内容或Test1
的任何子类型都是合法的至test
。但是,由于test1
的类型为Test2
,因此为Test1
指定类型Test1
的表达式是不合法的,因为Test2
不是test
的子类型。特别是,表达式Test1
的类型为Test1
,而Test2
不是test
的子类型。
请注意,这是一个编译时检查,它与test1 = (Test2) test;
在运行时可能具有的实际值的类型无关。如果您确定表达式实际上是较窄的类型,则可以使用强制转换:
ClassCastException
但是,如果test
的实际值不是Test2
类型(或其子类型),则会在运行时引发instanceof
。因此,在进行此类转换时,您将失去编译时类型检查的一些好处。通常使用int x = 1;
byte y = 2;
x = y; // okay
y = x; // ERROR -- requires a cast to narrow the type
y = (byte) x; // okay
运算符来检查强制转换是否成功。但是,如果你发现自己编程是这样的,那就是“代码味道”:表明你的代码设计可能在某些方面存在缺陷。
原始值也会发生类似的事情:
ClassCastException
与引用类型不同,基本类型的强制转换永远不会抛出{{1}}。