向下转型也是Java的一大特色。
生活中,我们可以认为鸟是一种动物,但是如果说动物是鸟,那显然违背常理了,同样的,编译器也很难接受这种事。
eg1:
class Father{
void fMethod(){
System. out.println( "father method!!!");
}
}
class Son extends Father{
void sMethod(){
System. out.println( "son method!!!");
}
}
public class test {
public static void main(String[] args){
Son son = (Son) new Father();
son.fMethod();//方法1
son.sMethod();//方法2
}
}
执行方法1、方法2,都是出现ClasscastException。
如果向下转型这样不给力的话,那就没有存在的必要了。
oracle工程师直接跟我们说,java不给向下转型就行了。
但是事实并非如此。这只是其一,还有其二。
eg2:
class Father{
void fMethod(){
System. out.println( "father method!!!");
}
}
class Son extends Father{
void sMethod(){
System. out.println( "son method!!!");
}
}
public class test {
public static void main(String[] args){
//声明一个儿子类型son1
Son son1 = new Son();
//将son1转换成父亲类型father,向上转型
Father father = (Father)son1;
//将father类型转换成son2,向下转型
Son son2 = (Son)father;
//执行
son2.fMethod();
son2.sMethod();
}
}
在eg2中,首先使用声明了一个子类型,将其转换成父类型,随后再将父类型转换成子类型,执行相关方法,编译器都通过了。
第2个例子中:Son son2 = (Son)father;问什么 是正确的呢。
很简单因为father指向一个子类对象,Father father = (Father)son1; 子类s2引用当然可以指向子类对象了。
这个时候,向下转型就又可以使用了,也许可以适用一些特殊的业务需求哦。
那么问题来了(VIP)?
程序员在使用向下转型时,哪知道这个父类引用指向的时哪个?也许是自己的对象,也许是子类对象,那代码就写不下去了。
大家一定知道
instanceof
运算符(很特殊的运算符哦)
吧,instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。
所以eg2中,可以在主函数这样写,就可以完美的避免这个问题啦。
//声明一个儿子类型son1
Son son1 = new Son();
//将son1转换成父亲类型father,向上转型
Father father = (Father)son1;
//将father类型转换成son2,向下转型
Son son2 = (Son)father;
//执行
if(son2 instanceof Son){
son2. fMethod();
son2.sMethod();
}
这种写法有点像防止c系语音中野指针出现的情况哦。