继承和引用类型转换

继承的初始化顺序

  1. 初始化父类再初始化子类
  2. 先执行初始化对象中的属性,再执行构造方法中的初始化

引用类型转换

  1. 向上类型转换(隐式/自动类型转换)是从小类型到大类型的转换。这种用法叫做“父类引用指向子类对象”,指的是定义一个父类的引用,而它实际指向的是子类创建的对象,如下例。
Animal animal = new Dog(); //自动类型提升,向上类型转换
  1. 向下类型转换(强制类型转换),是大类型到小类型的转换。
Animal animal = new Animal();//自动类型提升,向上类型转换
Dog dog2 = (Dog)animal; //向下类型转换,强制类型转换

可见向下转换存在溢出的风险。我们可以用instanceof运算符,来解决引用对象的类型,避免类型转换的安全性问题。

【示例】

Dog dog = new Dog();
Animal animal = dog(); //自动类型提升,向上类型转换
Dog dog2 = (Dog)animal; //向下类型转换,强制类型转换

上面代码中的向下类型转换是存在一定风险的。例如说我把父类应用转换成了cat类型的引用,虽然我强制把这个类型进行转换,但是毕竟我这个引用指向的是一个dog对象,显然它没有办法转换成cat对象,根本就是不同类型的对象。

Dog dog = new Dog();
Animal animal = dog(); //自动类型提升,向上类型转换
Dog dog2 = (Dog)animal; //向下类型转换,强制类型转换
Cat cat = (Cat)animal; 

虽然编译器没有检查出这个错误,但是当程序真正运行的时候会发现程序会有问题。因为我们真正开辟的运行空间是dog类型,程序运行的时候发现两个类型不匹配是不能进行类型转换的,所以出现了以下异常。


此时我们可以用instanceof运算符,来解决引用对象的类型:

Dog dog = new Dog();
Animal animal = dog(); //自动类型提升,向上类型转换
Dog dog2 = (Dog)animal; //向下类型转换,强制类型转换
if(animal instanceof Cat){
   Cat cat = (Cat)animal; //1.编译时cat类型 2.运行时dog类型
}else{
   System.out.println("无法进行类型转换");
}

向上引用之后调用子类还是父类的方法?

class A ...{  
     public String show(D obj)...{  
          return ("A and D");  
    }   
    public String show(A obj)...{  
          return ("A and A");  
    }   
}   
class B extends A...{  
     public String show(B obj)...{  
          return ("B and B");  
     }  
     public String show(A obj)...{  
          return ("B and A");  
     }    
}  
class C extends B...{}   
class D extends B...{}

问题:以下输出结果是什么?

A a1 = new A();  
A a2 = new B();  
B b = new B();  
C c = new C();   
D d = new D();   
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));      

答案

1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D

在这里看结果1、2、3还好理解,从4开始就开始糊涂了,对于4来说为什么输出不是“B and B”呢?

首先我们先看一句话:当超类对象引用变量引用子类对象时,如果子类重写了父类方法,向上造成后调用的是子类方法;子类没有重写父类方法,向上造型后调用的是父类方法。这句话对多态进行了一个概括。其实在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

首先我们分析5,a2.show(c),a2是A类型的引用变量,所以this就代表了A,a2.show(c),它在A类中找发现没有找到,于是到A的超类中找(super),由于A没有超类(Object除外),所以跳到第三级,也就是this.show((super)O),C的超类有B、A,所以(super)O为B、A,this同样是A,这里在A中找到了show(A obj),同时由于a2是B类的一个引用且B类重写了show(A obj),因此最终会调用子类B类的show(A obj)方法,结果也就是B and A。同理可以得出其他输出的原因。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Win7下如何打开DOS控制台? a:开始--所有程序--附件--命令提示符 b:开始--搜索程序和文件--cmd...
    逍遥叹6阅读 1,629评论 4 12
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 3,923评论 1 10
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,708评论 0 11
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,785评论 18 399
  • 生活中,很多人鼻子不够高,尤其是我们亚洲人种,天生塌鼻梁,进而造成了眼间距很宽,显得整张脸就会很宽,达不到现在大家...
    掉毛的兔子阅读 560评论 0 0