第八章:多态

来源:互联网 发布:mac迅雷无法下载 编辑:程序博客网 时间:2024/06/17 01:19
面向对象语言中,三大特性:封装,继承,多态

1.在论向上转型

对象可以作为他本身的类型使用,也可以作为他的基类型使用。这种把某个对象的引用视为对其基类的引用的做法被称为向上转型----因为在继承树上,基类是放置在最上方的。
package com.myboy.extendstest;class Instrument{public void play(int i){//int 可替换为其他的引用类型System.out.println("Instrument play()");}}public class Test5 extends Instrument{@Overridepublic void play(int i) {System.out.println("Test5 play()");}public static void main(String[] args) {Instrument test=new Test5();//多态体现test.play(3);//out:Test5 play()}}
多态:在Java中写了一个方法,它仅接收基类作为参数,而不是那些特殊的类。(为什么又能确定具体的对象引用?)

2.转机(解释为什么能确定具体的对象引用)

方法调用绑定:将一个方法同一个方法主体关联起来被称为绑定。若在程序中执行前进行绑定(由编译器确定),叫前期绑定。面向过程的语言中默认的绑定语言就是前期绑定。
后期绑定::是在运行的时根据对象的类型进行绑定,也称为后期绑定或运行时绑定。编译器一直不知道对象的类型,直到方法调用机制能找到正确的方法体,并加以调用。
Java中除了static 和final()方法(private方法属于final方法)之外,所有的方法都是后期绑定。
面向接口编程是最能体现的。
缺陷1:"覆盖"私有方法
package com.myboy.extendstest;class Test extends Test6{public void play(){System.out.println("Test play()");}}public class Test6 {private void play(){System.out.println("Test6 play()");}public static void main(String[] args) {Test6 t=new Test();t.play();//out "Test play()"  为什么,真是无语了}}
结论:(Java编程思想解释)只有非private 方法才可以被覆盖,但是由于private方法是自动被认为是final方法,而且对导出类是屏蔽的。因此,在这种情况下,Test类中的play()方法就是一个全新的方法;既然基类中play()不可见,不会被重载。需要密切注意覆盖private方法的现象,这是编译器虽然不会报错,但是也不会按照我们所期望的来执行。确定的说,在导出类中,对于基类中private方法,最好采用不同的名字。
缺陷2:域与静态方法
一旦了解了多态机制,可能会认为所有的事物都可以多态的发生。然而,只有普通的方法调用是可以多态的。这个访问就将在编译期进行解析。
package com.myboy.extendstest;class Super{public int field=0;public int getField(){return field;}}class Sub extends Super{public int field=1;public int getField(){return field;}public int getSuperField(){return super.field;}}public class FieldAccess {public static void main(String[] args) {Super sup=new Sub();System.out.println(""+sup.field+"|"+sup.getField());Sub sub=new Sub();System.out.println(""+sub.field+"|"+sub.getField()+"|"+sub.getSuperField());}/** * out 0|1 *     1|1|0 */}
当Sub对象转型为Super引用时,任何域访问操作都将有编译器解析。因此不是多态的。Super.field和Sub.field分配了不同的存储空间。这样,Sub实际上包含了两个成为field的域。在实际中,并不会出现,通常是将所有的域设计为private的,然后通过方法来访问(方法具有多态)
package com.myboy.extendstest;class StaticSuper{public static String getA(){return "A";}}class StaticSub extends StaticSuper{public static String getA(){return "B";}}public class StaticPolymo {public static void main(String[] args) {StaticSuper sub=new StaticSub();System.out.println(sub.getA());}//out A}
静态方法不具有多态性。静态方法是与类,而并非与单个的对象相关联。

3.协变返回类型

Java SE5中加了协变返回类型。
package com.myboy.extendstest;class Grain{@Overridepublic String toString() {// TODO Auto-generated method stubreturn "Grain";}}class Wheat extends Grain{@Overridepublic String toString() {return "Wheat";}}class Mill{public Grain process(){return new Grain();}}class WheatMill extends Mill{public Wheat process(){//Java SE5之前process()的覆盖版本必须返回为Grainreturn new Wheat();}}public  class Test7 {public static void main(String[] args) {Mill m=new Mill();System.out.println(m.process());m=new WheatMill();System.out.println(m.process());}/** * out Grain  *     Wheat */}

4.用继承进行设计(继承和组合的选择)

如何进行选择。一般而言,优先的选择方式是组合。组合更加的灵活,它可以动态选择类型(多态的完美体现),而继承在编译的时候就需要直接确切类型(后期绑定了具体的类型,无法在更改)。

5.向下转型和运行市类型识别

向上转型会丢失具体的类型信息。考虑向下转型(不安全)
package com.myboy.extendstest;class UserFul{public void a(){};}class User extends UserFul{public void a(){};public void b(){};}public class RTTI {public static void main(String[] args) {UserFul[] x= {new UserFul(),new User()};    x[0].a();    x[1].a();    //x[1]b()  方法找不到在UserFul    //((User)x[0]).b();  向下转型失败  ClassCastException    ((User)x[1]).b();//成功  运行时/RTTI}}

6.在论向上转型和向下转型

向上转型是注意的问题:基类指向子类引用对象会丢失掉与基类共有的其他方法。即子类中新的方法都会被丢失调,在编译时,系统会提示找不到子类的新方法。
向下转型:1.如果基类的引用的是导出类对象,那么在向下转型时就不会出现错误。
2.如果基类引用的是本身的话,编译时不会出错,但是运行时就会报ClassCastException,它可以用instanceof来避免此类错误。
class A{};class B extends A{};public class C{   main{       A a=new B();       B b=(B)a ;//正确       A c=new A();      B d=(B)c; //ClassCastException  }}


原创粉丝点击