`

java多态

阅读更多
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(a1.show(b));   ①
        System.out.println(a1.show(c));   ②
        System.out.println(a1.show(d));   ③
        System.out.println(a2.show(b));   ④
        System.out.println(a2.show(c));   ⑤
        System.out.println(a2.show(d));   ⑥
        System.out.println(b.show(b));     ⑦
        System.out.println(b.show(c));     ⑧
        System.out.println(b.show(d));     ⑨   
(三)答案

              ①   A and A
              ②   A and A
              ③   A and D
              ④   B and A
              ⑤   B and A
              ⑥   A and D
              ⑦   B and B
              ⑧   B and B
              ⑨   A and D

为什么答案是这样的,对象间是怎样调用的?
提问者: 因为复杂 - 六级
最佳答案
该问题的关键有两点:
一是子类与父类的关系,二是重载方法的调用问题。
    子类对象可以直接当成父类对象使用,但反过来就不可以。举例来说,人是父类,学生是人的子类,所以学生对象一定具备人对象的属性,但是人对象就未必具有学生对象的特性。所以学生对象可以当做人对象来使用,但是人对象就不能当做学生对象使用。注意当把子类对象当成父类对象使用时,子类对象将失去所有的子类特性,只保留与父类同名的属性和方法(同名方法不仅是函数名相同,而且参数类型也要一样,否则不予保留)。
    一个类中如果定义了重载的方法,则系统在调用方法时,会根据参数的类型自动选择调用合适的方法。

    1 a1.shows(b),在A中没有含有B类参数的方法,但是含有A类参数的方法,根据子类对象父类可用的原则,所以调用方法
     public String show(A obj)...{return ("A and A");}

    2 a1.show(c),C类是B类的子类,而B类又是A类的子类,所以C类对象可以当制作A类对象使用。结果同上。

    3 a1.show(d),根据参数类型直接调用A中的方法
      public String show(D obj)...{
                return ("A and D");
         }

    4 a2.show(b),a2本来是一个B对象,但是将其赋给了A类变量,所以a2只保留了与父类A同名的属性和方法。a2.show(b)调用B类中的保留的与父类同名同参方法
      public String show(A obj)...{
                return ("B and A");
         }

  5 a2.show(c),B类的保留方法中没有C类参数方法,但是有含有C的父类A的参数方法,所以调用的方法
             public String show(A obj)...{
                return ("B and A");
         }
     6 a2.show(d),调用的是A类中的
             public String show(D obj)...{
                return ("A and D");
         }
    7 b.show(b),调用B类中的
             public String show(B obj)...{
                return ("B and B");
         }
    8 b.show(c),B类中没有C类参数的方法,但是有B类参数的方法,所以调用方法          public String show(B obj)...{
                return ("B and B");
         }
    9 b.show(d),解释同8
你要明白这一点,多态这个做法..多态的作用就是能使你的程序更通用.
就比如:A a = new B;..这代码只能B只能是A的子类或子类的子子类也性.多态你所编写的类型(即A a;)必须是B你上级.换一种说法就比如:A就是动物,B就是猫,你可以把这只猫看作是动物.这样行吧.但你不能把一直动物看作是猫吧.即你所定义的类型必须是实际对象的父类,或是有间接的实现和继承的关系.

例子:A a = new B;就是说B要是间接或直接的继承类和实现接口.方可这样写.

1.第一个输出调用语句: a1.show(b); 你上面答案是"A and A" ;

你先看看:  A a2 = new B();  这里是泛化了吧.也就是说"B"类型可以说是"A"类型.
再看看: A a1 = new A(); 如果再调用a1.show(b);这里这个方法传进来的参数是"b"(即: 'B b = new B()');那么b你可以看作是个"A"类型的是吧?.可是A类里面有两个show()方法即方法重载.
请先看第一个方法:public String show(D obj)
方法里面接受的参数是D类型的.那么你能把B类型的看作是D类性的吗(即:你不可能把一只动物看作是猫吧.)? 即D类型不是B类型的父类.
再看看第二个方法:public String show(A obj)
这个方法就不用说了.这方法接受的参数是A类型的.那么B继承了A.也就可以说B类型的可以泛化成A类型的.还个角度说,就是猫可以看作是一个动物吧.
所以.第一个输出system.out.print(a1.show(b)),这结果自然是:"A and A"

以现实中的事情举个例子:

假设有一个“小提琴演奏者”类,有一个“钢琴演奏者”类,还有一个“萨克斯演奏者”类。它们都是弹奏乐器的,都继承自“乐器演奏者”类。“乐器演奏者”类有个方法叫做“演奏”。三种不同的子类有不同的“演奏”方法实现(拉、弹、吹)。

那么指挥家如果要指挥一个交响乐,那么有两个办法:
一,分别说“小提琴拉起来”、“钢琴弹起来”、“萨克斯吹起来”
二,只需要说一句“乐器们都演奏起来”

显然第一种方法是很笨拙的。因为指挥家不需要知道每种乐器演奏者具体怎么样去演奏乐器(是吹还是弹还是拉),他只需要指挥就可以了。因此应当采用第二种做法。
那么如何实现第二种做法呢?那就是把三种乐器演奏者子类看成是“乐器演奏者”父类。指挥家只需要调用“演奏”方法就可以了。至于具体是怎么去演奏,指挥家是不管的。

虽然代码上写的是把具体的演奏者子类看成了父类,调用的是父类的“演奏”方法,但是因为子类继承了父类的“演奏”方法并且重写为更加具体的实现(拉或者弹或者吹),创建实例的时候创建的是子类的实例(构造方法是子类的,只不过看成是父类去用),所以实际执行的时候会去调用子类的“演奏”方法。因此,究竟是该拉还是该弹还是该吹,指挥家不必在意,这个判断由java虚拟机完成了。

这个就是一个多态的应用

综合各个方面的问题,我个人总结了其它人的答案,并且加入些容易理解的解释,希望对你有好处
1 a1.shows(b),在A中没有含有B类参数的方法,但是含有A类参数的方法,根据子类对象父类可用的原则,所以调用方法
     public String show(A obj)...{return ("A and A");}

    2 a1.show(c),C类是B类的子类,而B类又是A类的子类,所以C类对象可以当制作A类对象使用根据子类对象父类可用的原则。结果同上。

    3 a1.show(d),根据参数类型直接调用A中的方法
      public String show(D obj)...{
                return ("A and D");
         }

    4 a2.show(b),a2本来是一个B对象,但是将其赋给了A类变量,所以a2只保留了与父类A同名的属性和方法。就是说只能调用 public String show(D obj)...{
                return ("A and D");
         }
和 public String show(A obj)...{
                return ("B and A");
         }
方法根据子类对象父类可用的原则a2.show(b)调用后者,所以:public String show(A obj)...{
                return ("B and A");
         }

  5 a2.show(c),B类的保留方法中没有C类参数方法,但是有含有C的父类A的参数方法,所以调用的方法
             public String show(A obj)...{
                return ("B and A");
         } 备注4和5的关系类似于1和2的关系
     6 a2.show(d),调用的是A类中的(为什么调用A类的方法,在4中已经说明)
             public String show(D obj)...{
                return ("A and D");
         }
    7 b.show(b),调用B类中的
             public String show(B obj)...{
                return ("B and B");
         }这个是比较直接的,应该容易理解吧
    8 b.show(c),B类中没有C类参数的方法,但是有B类参数的方法,所以调用方法(更加详细请看第一条 )        public String show(B obj)...{
                return ("B and B");
         }
    9 b.show(d),解释同8

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics