浅入浅出:关于多态、向上转型和向下转型的理解

写的不是很长,尽可能简洁清晰把知识串联起来理解吧。 

提纲:

1、instanceof

2、声明类型的强制转换

3、多态、向上转型和向下转型

1、instanceof

用于判断两个类之间是否存在父子关系。

是双目运算符,作用是测试它左边的对象是否是它右边的类的实例。比较的时候我们只看实际类型——就是new后面的对象所属类——和instanceof右边类之间的关系。

代码示例: 

Object object = new Student();  
System.out.println(object instanceof Student);   //ture
System.out.println(object instanceof Person);    //ture
System.out.println(object instanceof Object);   //ture
System.out.println(object instanceof Teacher);   //False
System.out.println(object instanceof String);   //False


Person person = new Student();  
System.out.println(person instanceof Student);   //ture
System.out.println(person instanceof Person);    //ture,
System.out.println(person instanceof Object);   //Ture
System.out.println(person instanceof Teacher);   //False
System.out.println(person instanceof String);   //编译报错

Student student = new Student();  
System.out.println(student instanceof Student);   //ture
System.out.println(student instanceof Person);    //ture,
System.out.println(student instanceof Object);   //Ture
System.out.println(student instanceof Teacher);   //编译报错
System.out.println(student instanceof String);   //编译报错

2、声明类型的强制转换

在基本类型里,高容量数据类型转低容量数据类型是强制转换。在对象里也一样,转换的是声明类型父类代表高的一方,子类代表低的一方。将声明类型从父类转换为子类,就是强制转换(向下转型)

被父类引用指向的子类对象(Father son)不能使用子类独有的方法,需强转后才可使用:

public class Father {
    public void run(){
        System.out.println("father run");
    }
}
=================================================

public class Son extends Father{
    public void go(){
        System.out.println("son go");
    }
}
=================================================
    @Test
    public void test(){
        Father son = new Son();   子类可以直接转父类。
        son.run();
//        son.go();               编译不通过!
        Son son2 = (Son) son; 
        son2.go();                通过强转后可以使用了
    }

输出:father run
son go

 注意,如果实际类型是父类的,声明类型不能转换为子类,编译不会报错但运行会报错 :

        Father father = new Father();
        Son father1 = (Son) father;//编译通过了
        father1.go();  //类型转换异常ClassCastException: class Father cannot be cast to class Son

总结:

  • 实际类型是子类、声明类型是子类的,可以转换为父类,也可以再从父类转换为子类(强转)。
  • 实际类型是父类、声明类型是父类的,不能转换为子类。

简而言之,实际类型是子类的,声明类型可以是父类或子类;

实际类型是父类的,声明类型只能是父类。

3、多态、向上转型和向下转型

令父类引用指向子类对象就是 向上转型,父类代表高的一方,子类代表低的一方。

3.1 父类引用指向子类对象的好处?


1.如果这个父类是抽象类,抽象类本身不能实例化,就必须通过子类来达到目的。

2.限定了调用方法的范围,达到封装的安全性。   此种情况下,不能调用子类定义的(特有的)方法,只能调用父类定义过的方法,且运行时实际用的是子类覆写父类后的。我们在编译期只能调用父类中声明的方法,但执行期/运行期,我们实际执行的是子类重写父类的方法——虚拟方法调用。【即:编译看左边(类),运行看右边(类)】

只有声明类型是自己时,才可以调用自己定义的属性和方法。之所以这么做是为了规范,因为类里可能有很多东西并非用户需要的,用户只需要通过某个“外接口”来获取对象并操作它就可以了,这就是封装。缺点却也是优点。

3. 方便修改,降低了修改程序的成本和风险。比如

HashMap<Integer,String> map = new HashMap<>();

这种情况,如果要用其他Map(这是一个接口)的其他实现类(比如能力更为强大的SuperMap),注意你有可能在后续代码里用到了HashMap的独有方法,这时改成SuperMap就需要改一系列被波及的代码,成本极大,也有很大的风险隐患。如果改成下面这种

Map<Integer,String> map = new HashMap<>();

由于使用的是接口的方法,由于所有实现类都对它进行了重写,需要调整为其他类的时候就非常灵活,最好的情况是,只需把new HashMap<>()这行替换掉即可。

3.2 什么是多态?条件?作用?

通过子类重写父类方法表现不同特性就是多态。

多态的条件?

1.继承关系 2.子类重写父类方法 3.通过父类引用调用重写后的方法(向上转型)
多态的作用?

1.通过子类重写父类方法,表现不同的特性  2.减少(子类之间的)方法重载,不用子类特别去造方法,避免代码冗余,比如在没有多态性的情况下,一个方法声明什么类型的参数,就只能用这个类型的对象去传,这就需要写很多同种功能的方法,造成了方法冗余。

对象的多态性只适用于方法,不适用于属性,Person p2 = new Man();此时打印父类和子类同名的属性时,输出的是父类的属性值。【属性 编译看左边】

Father son = new Son();   

 如上,不能调用子类所特有的方法、属性,编译时,p2是Person类。
 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但由于变量声明为父类类型,导致编译时只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用(声明了,但p2不能调用!)。所谓【编译看左边】。
问如何才能调用子类特有的属性和方法? 答:向下转型,Son son2 = (Son) son; 也就是强制转换。


 3.3 向下转型及其条件:

令声明类型从父类转换为子类,就是向下转型

向下转型的对象其实际类型须是本类或其子类,转换到本类或父类。反之,因为父类没有子类特定的功能,因此不能转、不合法! 要想向下转型,new的一定不是父类,而是本类或子类,然后强转回来。总结一句话:功能少的不可以转换为功能多的。

(根据自己的理解整理,如有错误欢迎指正!)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值