java中面向对象一定要区分两个概念,父类变量和父类对象以及子类变量和子类对象,父类变量/子类变量(类似于C++中的指针概念)指向了父类对象/子类对象,变量中存了堆中对象的地址。
1、多态(向上转换)
编译器编译时,只知道父类变量的类型,而编译器运行时,实际运行的是父类对象,此时类型发生了转换,所以就可以据此实现多态,让父类变量指向子类对象,编译器编译时,认为是父类变量的类型,而运行时候,则变成了子类对象的类型,这就是向上转换;
2、向下转换
除了子类对象赋值给父类变量以为,还有一种情况就是,父类对象(实例)赋值给子类变量,这种情况是不允许的,虽然可以通过强制转换,编译时不报错,但是运行时,会产生ClassCastException异常,因为子类的很多方法是父类不具有的,所以不能这样赋值。除此之外,如果是父类变量指向了子类对象,然后将父类变量赋值给子类变量,这种情况是可以的,就相当于将子类对象的地址赋值给子类变量,不过仍然需要类型转换。
结果报错:
结果不报错:
实际原理也很好理解,因为运行的时候,是运行的对象,而不是父/子类变量,所以如果本来指向的是父类对象,将父类变量转换成子类变量来赋值,编译时可以通过,但子类变量会指向父类对象,所以会导致类型转换异常。