《Java 编程思想》第8章 多态 笔记

第8章 多态

一,向上转型
由导出类转型为基类,在继承图上是向上移动,因此一般称为向上转型。换句话说,把导出类类对象直接赋给基类引用叫upcasting向上转型。

package other;
enum Note{
    MIDDLE_C,C_SHARP,B_FLAT;
}
class Instrument{
    public void play(Note n){
        System.out.println("Instrument play()");
    }
    @Override
    public String toString() {
       return  "Instrument!";
    }
}
class Wind extends Instrument{
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "Wind!";
    }
    @Override
    public void play(Note n) {
        System.out.println("Wind play()"+n);
    }
    public void Sound(){
         System.out.println("Wind Sound()!");
    }
}
class Brass extends Instrument{
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "Brass!";
    }
    @Override
    public void play(Note n) {
        System.out.println("Brass play()"+n);
    }
    public void Sound(){
         System.out.println("Brass Sound()!");
    }
}
public class Music {
    public static void tune(Instrument i){
        i.play(Note.MIDDLE_C);
    }
    public static void main(String[] args) {
        Instrument b=new Brass();
        Instrument w=new Wind();
        System.out.println(b);
        w.play(Note.C_SHARP);
        tune(b);
        ((Wind) b).Sound();
    }
}

输出结果:
Brass!
Wind play()C_SHARP
Brass play()MIDDLE_C
向上转型:
Instrument b=new Brass();
Instrument w=new Wind();
System.out.println(b);调用Brass的toString(),输出Brass!
w.play(Note.C_SHARP);调用Wind的play(),输出Wind play()C_SHARP
向上转型的好处:
public static void tune(Instrument i);
这里以基类引用为参数,调有时用导出类引用作为参数,就是利用了向上转型。这样使代码变得简洁。不然的话,就要为每一个导出类都编写一个新的tune(),这也体现了JAVA的抽象编程思想。
当然,导出类向上转型到基类可能会“缩小”接口,但不会比基类的全部接口更窄。需要注意的是向上转型时会遗失除与父类对象共有的其他方法。如本例中的Sound()方法不再为b所有。
((Wind) b).Sound();这时会提示进行类型的显性转换,但是转换不成功,抛出java.lang.ClassCastException异常。

二,方法调用绑定
将一个方法调用和一个方法主体关联起来称作绑定,若程序在执行前进行绑定(由编译器和连接程序实现),叫做前期绑定,比如static方法和final方法(private方法属于final方法)。在运行时根据对象的类型进行绑定称为后期绑定,也叫做动态绑定。后期绑定也解决了编辑器只有一个基类引用时,究竟该调用哪个方法的问题。

public static void tune(Instrument i){
        i.play(Note.MIDDLE_C);
    }

Instrument引用对play()的调用都是通过后期绑定进行的。
通过这样,tune()方法可以忽略周围代码所发生的变化,依旧正常运行,换句话说:多态是一项将改变的事物和未变的事物分离开来的技术。
但是其中也存在一些问题要注意,以下都不具有多态性;
1,private方法

package other;
class Dervied extends PrivateOverride{
    public void f(){
        System.out.println("public f()");
    }
}
public class PrivateOverride {
    private void f(){
        System.out.println("private f()");
    }
    public static void main(String[] args) {
         PrivateOverride p=new Dervied();//向上转型
         p.f();
    }
}

输出是private f(),只有非private方法才可以被重载覆盖,基类中的f()对于子类Derived是不可见的,所以也无法进行重载。在导出类中,对于基类中的private方法,最好采用不同的命名。

2,类中的域不具有多态性

class Super{
    public int field=1;
    public int getField(){
        return field;
    }
}
class Sub extends Super{
    public int field=2;
    public int getField(){
        return field;
    }
}
public class Test7 {
    public static void main(String[] args) {
        Super sub=new Sub();//向上转型
        System.out.println("sub.field="+sub.field+","+"sub.getfield()="+sub.getField());
    }
}

输出结果:sub.field=1,sub.getfield()=2,类中的域是在运行前就解析赋初值了。因此Super和Sub中的field分别分配不同的存储空间。他们各不相干,但是在实际中,这个问题也不太会发生,首先,类中的域都被设置成private,不能直接访问,可以调用方法访问,其次,基类和导出类的域命名都是不同的

3,静态方法,它的行为就不具有多态性,因为static在运行前就已经被绑定。

你可能感兴趣的:(Java)