• Java面向对象编程三大特性 --- 多态


    多态特性:

           子类Child继承父类Father,我们可以编写一个指向子类的父类类型引用,该引用既可以处理父类Father对象,也可以处理子类Child对象,当相同的消息发送给子类或者父类对象时,该对象就会根据自己所属的引用而执行不同的行为,这就是多态。即多态性就是相同的消息使得不同的类做出不同的响应。

     1 /**
     2  * 多态特性
     3  *
     4  * @author Wáng Chéng Dá
     5  * @create 2017-02-21 14:39
     6  */
     7 class Father {
     8     String x = "Father--x";
     9     static String y = "Father--y";
    10 
    11     void eat() {
    12         System.out.println("Father喜欢吃大蒜!");
    13     }
    14 
    15     static void speak() {
    16         System.out.println("Father:儿子去写作业!");
    17     }
    18 }
    19 
    20 class Son extends Father {
    21     String x = "Son--x";
    22     static String y = "Son--y";
    23 
    24     void eat() {
    25         System.out.println("Son喜欢爽歪歪!");
    26     }
    27 
    28     static void speak() {
    29         System.out.println("Son:爸爸我可不可以不写作业, 练字啊?");
    30     }
    31 }
    32 
    33 public class Polymorphic {
    34 
    35     public static void main(String[] args) {
    36 
    37         System.out.println("---------父类引用指向子类对象[Father f = new Son()]START-----------");
    38         Father f = new Son(); // 父类引用指向了子类对象。
    39         System.out.println(f.x);
    40         System.out.println(f.y);
    41         f.eat();
    42         f.speak();
    43         System.out.println("---------父类引用指向子类对象[Father f = new Son()]END-----------");
    44 
    45 
    46         System.out.println("---------[Son son = new Son()]START-----------");
    47         Son son = new Son();
    48         System.out.println(son.x);
    49         System.out.println(son.y);
    50         son.eat();
    51         son.speak();
    52         System.out.println("---------[Son son = new Son()]END-----------");
    53 
    54 
    55         System.out.println("---------[Father father = new Father()]START-----------");
    56         Father father = new Father();
    57         System.out.println(father.x);
    58         System.out.println(father.y);
    59         father.eat();
    60         father.speak();
    61         System.out.println("---------[Father father = new Father()]END-----------");
    62 
    63 
    64         System.out.println("---------[Son s = new Father()]START-----------");
    65         System.out.println("Son s = new Father()--子类引用指向父类会编译失败");
    66         System.out.println("---------[Son s = new Father()]END-----------");
    67 
    68     }
    69 }

    控制台输出:

    ---------父类引用指向了子类对象[Father f = new Son()]START-----------
    Father--x
    Father--y
    Son喜欢爽歪歪!
    Father:儿子去写作业!
    ---------父类引用指向了子类对象[Father f = new Son()]END-----------
    ---------[Son son = new Son()]START-----------
    Son--x
    Son--y
    Son喜欢爽歪歪!
    Son:爸爸我可不可以不写作业, 练字啊?
    ---------[Son son = new Son()]END-----------
    ---------[Father father = new Father()]START-----------
    Father--x
    Father--y
    Father喜欢吃大蒜!
    Father:儿子去写作业!
    ---------[Father father = new Father()]END-----------
    ---------[Son s = new Father()]START-----------
    Son s = new Father()--子类引用指向父类会编译失败
    ---------[Son s = new Father()]END-----------

    总结:

    1:父类和子类有相同的成员变量 , 多态下访问的是父类的成员变量。 
    2:当子类重写父类非静态方法,多态下访问的是子类的非静态方法。 
    3:当子类重写父类静态方法,多态下访问的是父类的静态方法。

    多态的实现:

    Java实现多态有三个必要条件:继承、重写、向上转型

    继承:就是扩展已有类的功能,在继承中分为子类和父类,父类有时候也称为超类(super class),子类有时候称为派生类(一个父类可以有多个子类,一个子类必须只有一个父类)。

    重写:子类对父类中某些方法进行重新定义(方法同时存在父子类关系中)。

    向上转型:一个指向子类的父类类型引用[Father f = new Child()]。

     1 class Wine {
     2     private String name;
     3 
     4     public String getName() {
     5         return name;
     6     }
     7 
     8     public void setName(String name) {
     9         this.name = name;
    10     }
    11 
    12     public Wine(){
    13     }
    14 
    15     public String drink(){
    16         return "喝的是 " + getName();
    17     }
    18 
    19     /**
    20      * 重写toString()
    21      */
    22     public String toString(){
    23         return "Wine中重写toString()";
    24     }
    25 }
    26 
    27 class Beer extends Wine{
    28     public Beer(){
    29         setName("啤酒");
    30     }
    31 
    32     /**
    33      * 重写父类方法,实现多态
    34      */
    35     public String drink(){
    36         return "喝的是 " + getName();
    37     }
    38 
    39     /**
    40      * 重写toString()
    41      */
    42     public String toString(){
    43         return "Wine : " + getName();
    44     }
    45 }
    46 
    47 class RedWine extends Wine{
    48     public RedWine(){
    49         setName("红酒");
    50     }
    51 
    52     /**
    53      * 重写父类方法,实现多态
    54      */
    55     public String drink(){
    56         return "喝的是 " + getName();
    57     }
    58 
    59     /**
    60      * 重写toString()
    61      */
    62     public String toString(){
    63         return "Wine : " + getName();
    64     }
    65 }
    66 
    67 public class Test {
    68     public static void main(String[] args) {
    69         //定义父类数组
    70         Wine[] wines = new Wine[2];
    71         //定义两个子类
    72         Beer beer = new Beer();
    73         RedWine redWine = new RedWine();
    74 
    75         //父类引用子类对象
    76         wines[0] = beer;
    77         wines[1] = redWine;
    78 
    79         for(int i = 0 ; i < 2 ; i++){
    80             System.out.println(wines[i].toString() + "
    这杯" + wines[i].drink());
    81             System.out.println("-------------------------------");
    82         }
    83     }
    84 }

    控制台输出:

    Wine : 啤酒

    这杯喝的是 啤酒

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

    Wine : 红酒

    这杯喝的是 红酒

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

    特性:

    1. 当子类重写父类的方法被调用时,只有对象继承链中的最末端的方法才会被调用。

    2. 对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。

    经典实例

     1 class A {
     2     public String show(D obj) {
     3         return ("A and D");
     4     }
     5 
     6     public String show(A obj) {
     7         return ("A and A");
     8     }
     9 
    10 }
    11 
    12 class B extends A{
    13     public String show(B obj){
    14         return ("B and B");
    15     }
    16 
    17     public String show(A obj){
    18         return ("B and A");
    19     }
    20 }
    21 
    22 class C extends B{
    23 
    24 }
    25 
    26 class D extends B{
    27 
    28 }
    29 
    30 class Test {
    31     public static void main(String[] args) {
    32         A a1 = new A();
    33         A a2 = new B();
    34         B b = new B();
    35         C c = new C();
    36         D d = new D();
    37         System.out.println("A----B----C");
    38         System.out.println("     ┖----D");
    39         System.out.println("this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)");
    40 
    41         System.out.println("1--" + a1.show(b));
    42         System.out.println("2--" + a1.show(c));
    43         System.out.println("3--" + a1.show(d));
    44         System.out.println("4--" + a2.show(b));
    45         System.out.println("5--" + a2.show(c));
    46         System.out.println("6--" + a2.show(d));
    47         System.out.println("7--" + b.show(b));
    48         System.out.println("8--" + b.show(c));
    49         System.out.println("9--" + b.show(d));
    50     }
    51 }

    控制台输出:

    A----B----C
    ┖----D
    this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)
    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)

            比如4,a2.show(b),a2是一个引用变量,类型为A,则this为a2,b是B的一个实例,于是它到类A里面找show(B obj)方法,没有找到,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为B,(super)O即(super)B即A,因此它到类A里面找show(A obj)的方法,类A有这个方法,但是由于a2引用的是类B的一个对象,B覆盖了A的show(A obj)方法,因此最终锁定到类B的show(A obj),输出为"B and A”。

            再比如8,b.show(c),b是一个引用变量,类型为B,则this为b,c是C的一个实例,于是它到类B找show(C obj)方法,没有找到,转而到B的超类A里面找,A里面也没有,因此也转到第三优先级this.show((super)O),this为b,O为C,(super)O即(super)C即B,因此它到B里面找show(B obj)方法,找到了,由于b引用的是类B的一个对象,因此直接锁定到类B的show(B obj),输出为"B and B”。

    当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

  • 相关阅读:
    Java之内存分析和String对象
    Android之MVC模式
    Java之排序总结
    Android之单元测试学习
    Silverlight 拖拽功能
    Silverlight 调用WebServices
    Silverlight IIS 7.5 部署SilverLight4网站以及问题解决
    Silverlight 控件和对话框 源自MSDN 参考
    Silverlight 动画示例
    Sliverlight 动画详细介绍
  • 原文地址:https://www.cnblogs.com/chinda/p/6427328.html
Copyright © 2020-2023  润新知