在java中强制类型转换分为基本数据类型和引用数据类型两种,这里咱们讨论的后者,也就是引用数据类型的强制类型转换。java
在Java中因为继承和向上转型,子类能够很是天然地转换成父类,可是父类转换成子类则须要强制转换。由于子类拥有比父类更多的属性、更强的功能,因此父 类转换为子类须要强制。那么,是否是只要是父类转换为子类就会成功呢?其实否则,他们之间的强制类型转换是有条件的。函数
当咱们用一个类型的构造器构造出一个对象时,这个对象的类型就已经肯定的,也就说它的本质是不会再发生变化了。在Java中咱们能够经过继承、向上转型的关系使用父类类型来引用它,这个时候咱们是使用功能较弱的类型引用功能较强的对象,这是可行的。可是将功能较弱的类型强制转功能较强的对象时,就不必定能够行了。布局
举个例子来讲明。好比系统中存在Father、Son两个对象。首先咱们先构造一个Son对象,而后用一个Father类型变量引用它:post
Father father = new Son();spa
在这里Son对象实例被向上转型为father了,可是请注意这个Son对象实例在内存中的本质仍是Son类型的,只不过它的能力临时被消弱了而已,若是咱们想变强怎么办?将其对象类型还原!指针
Son son = (Son)father;code
这条语句是可行的,其实father引用仍然是Father类型的,只不过是将它的能力增强了,将其增强后转交给son引用了,Son对象实例在son的变量的引用下,恢复真身,可使用所有功能了。对象
每次转载,我都会附加本身的感想和有关的知识点,此次也不例外:blog
-----------------------------------------------------------------------------------------------------------------------继承
上面提到一句特别重要的话:当 咱们用一个类型的构造器构造出一个对象时,这个对象的类型就已经肯定的,也就说它的本质是不会再发生变化了。各类类型的转换,只不过是他的能力被临时消弱 了而已(能力被削弱的意思是你访问这个对象用的指针能看到这个对象的多少的功能,虽然这个对象有不少的功能摆在那里),其本质的东西并无任何的变化(这 句话是重点)。看下面的一段Java的代码:
1 public class TestCastClassException 2 { 3 public static void main(String[] args) 4 { 5 Father father = new Son(); 6 7 //这两句话是不对的,由于一个father类型的引用(指针)是看不见、看不到son中新定义的数据成员或者成员函数的 8 //虽然这个对象的本质是Son类型的,它也确实有这样的数据成员和成员函数,可是指针的做用范围不够,它看不到。 9 //代码后面附上模型分析 10 //father.son = 2; 11 //father.show_son(); 12 13 father.show_father(); 14 father.show(); 15 Father father1 = (Father)father;//一个对象在内存中被new出来后,只能选择访问它的方式,不能修改它的布局(包含的成员的个数等) 16 father1.show(); 17 18 } //main 19 } 20 21 class Father 22 { 23 public int father = 2; 24 Father(){} 25 26 void show() 27 { 28 System.out.println("This is father"); 29 } 30 31 void show_father() 32 { 33 System.out.println("father!!"); 34 } 35 } 36 37 class Son extends Father 38 { 39 public int son = 1; 40 Son(){} 41 void show() 42 { 43 System.out.println("This is son"); 44 } 45 46 void show_son() 47 { 48 System.out.println("son!!"); 49 } 50 }
下面是具体的模型,咱们以C++的虚函数模型类比Java:
解释:若是子类中有和父类同样的函数,那么子类的函数会覆盖父类的 相同的函数,这种覆盖叫作重写,这种覆盖的行为表如今子类对象中继承父类的那部分的成员函数指针部分的相同函数被覆盖。然而子类中的成员函数的指针中并没 有相应的函数。如上面的show()函数,子类重写以后,直接覆盖继承父类的本来的show()函数,本身没有必要留有备份。
还有就是一旦这个son对象被new出来以后,他在内存中的本质就 不会改变,我该有的就是个人,用Father类型的指针来访问这个对象的时候,Father类型的指针的做用范围是有限的,只能看到子类继承自父类的那部 分,固然他能看到被重写的show()函数,这也就是多态的实现。要想看到son中新定义的数据成员和成员函数,必须用Son类型的指针来访问这个对象。
还有就是一旦某个对象被new出来后,咱们只能选择不一样的指针来选择访问它的方式,固然也能修改其中的某个数据成员的值,可是不能修改其数据成员的个数和成员函数的个数,也就是说这个对象的本质是不会变的了。
-----------------------------------------------------------------------------------------------------------------------
前面提到父类强制转换成子类并非老是成功,那么在什么状况下它会失效呢?
当引用类型的真实身份是父类自己的类型时,强制类型转换就会产生错误。例如:
Father father = new Father();
Son son = (Son) father;
这个系统会抛出ClassCastException异常信息。
因此编译器在编译时只会检查类型之间是否存在继承关系,有则经过;而在运行时就会检查它的真实类型,是则经过,不然抛出
ClassCastException异常。
因此在继承中,子类能够自动转型为父类,可是父类强制转换为子类时只有当引用类型真正的身份为子类时才会强制转换成功,不然失败。