美文网首页
java多态复习

java多态复习

作者: 咕噜__ | 来源:发表于2018-08-21 18:55 被阅读0次

最近在复习java基础,在多态上面有一些不太明白的地方,故记录下来供自己时时复习查阅巩固。

概述

我们都知道面向对象有三大特性,封装,继承,多态。封装很好理解,就是对于数据的保护机制,对外部隐藏内部的实现细节,仅仅暴露访问方法,这样的好处在于对于业务来说不用关心实现细节,而当实现细节需要改变时,也不会影响外部业务,可以说,封装是解耦的基础,也是面向对象思想的缩影。

继承和多态往往会把它们放在一起讲,继承是为了重用父类并对父类进行扩展,正式因为有了继承,才导致了多态的出现,那么多态到底定义是什么呢?所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

什么意思呢?比如有一个汽车类Car,车库里面有奔驰Benz、宝马BMW、比亚迪BYD,那么可以有如下构建方法

Car a = new Benz();

Car b = new BMW();

Car c = new BYD();

我们事前并不知道这辆车是什么车,只有当它开出来我们才能知道,这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象。

向上转型

要理解多态就要知道什么叫向上转型,在上述例子中,如果只是像如下创建

Benz a = new Benz();

那就只是一个单纯的实例化了一个Benz对象,但是如果是这样呢?

Car a = new Benz();

我们可以看到,我们定义了一个Car的引用,指向了Benz实例对象,可以这样的原因是Benz继承于Car,所以Benz可以转型为Car,这个过程就叫做向上转型。这样做存在一个非常大的好处,在继承中我们知道子类是父类的扩展,它可以提供比父类更加强大的功能,如果我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能。

但是向上转型存在一些缺憾,那就是它必定会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性无法调用。

public class Wine {

    public void fun1(){

        System.out.println("Wine 的Fun.....");

        fun2();

    }

    public void fun2(){

        System.out.println("Wine 的Fun2...");

    }

}

public class JNC extends Wine{

    /**

    * @desc 子类重载父类方法

    *        父类中不存在该方法,向上转型后,父类是不能引用该方法的

    * @param a

    * @return void

    */

    public void fun1(String a){

        System.out.println("JNC 的 Fun1...");

        fun2();

    }

    /**

    * 子类重写父类方法

    * 指向子类的父类引用调用fun2时,必定是调用该方法

    */

    public void fun2(){

        System.out.println("JNC 的Fun2...");

    }

}

public class Test {

    public static void main(String[] args) {

        Wine a = new JNC();

        a.fun1();

    }

}

-------------------------------------------------

Output:

Wine 的Fun.....

JNC 的Fun2...

分析:在这个程序中子类JNC重载了父类Wine的方法fun1(),重写fun2(),而且重载后的fun1(String a)与 fun1()不是同一个方法,由于父类中没有该方法,向上转型后会丢失该方法,所以执行JNC的Wine类型引用是不能引用fun1(String a)方法。而子类JNC重写了fun2() ,那么指向JNC的Wine引用会调用JNC中fun2()方法。

 所以对于多态我们可以总结如下:

多态的必要条件有3个,继承,重写,向上转型。指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。

再看一个经典例子

public class A {

    public String show(D obj) {

        return ("A and D");

    }

    public String show(A obj) {

        return ("A and A");

    }

}

public class B extends A{

    public String show(B obj){

        return ("B and B");

    }

    public String show(A obj){

        return ("B and A");

    }

}

public class C extends B{

}

public class D extends B{

}

public class Test {

    public static void main(String[] args) {

        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. a1.show(b),由于B extends A,所以真正调用的是A.show(A)

2.a1.show(c),由于C extends B,B extends A,所以真正调用的是A.show(A)

3.a1.show(d),直接调用A.show(D)

4.a2.show(b),可能这里会疑惑为什么不是B and B,原因在于虽然B继承了A,但是父类A中其实是没有show(B)这个方法的,上面有说到, 指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,所以最后是调用的B类的show(A)方法,因为B继承A。

5.a2.show(c),同4理。

6.a2.show(d),父类中存在show(D)方法,而子类B并没有重写,所以直接调用A.show(D)

7. b.show(b),b是创建的B对象,也是B的引用,不存在向上转型,所以直接调用B.show(B)

8.b.show(c),父类A中没有show(C)方法,所以会调用子类,又由于C继承于B,B继承于A,在调用中,会调用继承关系最近的那一个,所以直接调用B.show(B)

9.b.show(d),父类A中有方法show(D),而子类B中并没有重写,所以直接调用A.show(D)

通过上面例子可以发现一个事实,在继承链中对象方法的调用存在一个优先级: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。

相关文章

  • java多态复习

    最近在复习java基础,在多态上面有一些不太明白的地方,故记录下来供自己时时复习查阅巩固。 概述 我们都知道面向对...

  • JAVA复习之多态

    概述: 面试题: java实现多态的机制是什么? 靠的是父类或接口引用指向自己子类对象的实例;而程序调用的方法在运...

  • java多态面试题

    java多态性 多态分两种: (1) 编译时多态(设计时多态):方法重载。 (2) 运行时多态:JAVA运...

  • java多态面试题

    java多态性 多态分两种: (1) 编译时多态(设计时多态):方法重载。 (2) 运行时多态:JAVA运行时...

  • 2018-01-25

    多态机制 java语言,实现多态...

  • java多态之简述

    Java的第三大特性------>多态 一、什么是多态 多态根据其字面意思就是多种形态的意思,那么在Java中的多...

  • 学习JavaScript设计模式——面向对象(五)

    面向对象(五) 多态 我仔细看了一下,这里说的JavaScript 的多态好像和Java的多态不一样, Java ...

  • Java基础之面向对象

    1.多态,继承,封装 Java实现多态有哪些必要条件?具体怎么实现?多态的实现原理?多态的作用? 答:多态的优点 ...

  • Java 多态

    1、Java 多态分类 1)编译时多态:方法重载。2)运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决...

  • Java 多态之方法调用顺序

    本文例子取于<深入理解java多态性>和,分析 Ja...

网友评论

      本文标题:java多态复习

      本文链接:https://www.haomeiwen.com/subject/kvwjiftx.html