重识Java多态

2018-03-24  本文已影响83人  r09er

今天面试被问到了Java多态的知识点

面试官:  了解多态吗,说一说你对多态的理解

我: balabala..

面试官: 知道多态是如何实现的吗

我: 涉及到了我的知识盲区...

赶紧回去拿起Thinking In Java看一遍多态的章节..

作为面向对象中的一个重要特征,多态的原理必须要掌握.
多态:

多态通过分离做什么怎么做,从另一个角度将接口和实现分离开来,多态不但能够改善代码的组织结构和可读性,还能创建可拓展的程序.

  多态也被称为动态绑定,后期绑定或运行时绑定.

方法调用绑定

在考虑这个问题之前先看一段代码

public enum Note {
    MIDDLE_C, C_SHARP, B_FLAT;
}
public class Instrument {
    public void play(Note note) {
        System.out.println("Instrument.play()");
    }
}
public class Wind extends Instrument {
    @Override
    public void play(Note note) {
        System.out.println("Wind.play()" + note);
    }
}
public class Bass extends Instrument {
    @Override
    public void play(Note note) {
        System.out.println("Bass.play*() " + note);
    }
}

public class Music {
    private static void tune(Instrument instrument) {
        instrument.play(Note.MIDDLE_C);
    }
    public static void main(String[] args) {
        Wind wind = new Wind();
        Bass bass = new Bass();
        tune(wind);
        tune(bass);
    }
}

这段代码就是典型的多态运用,面向抽象和基类编程,依赖于抽象和基类,而不是依赖于具体实现.

private static void tune(Instrument instrument) {
        instrument.play(Note.MIDDLE_C);
}

在tune方法中,接收一个Instrument对象,在这种情况下,编译器是如何知道Instrument引用指向Wind对象还是Bass呢?实际上编译期是无法得知的.

那要如何正确引用正确的对象呢?

解决办法就是通过对象的后期绑定,在运行时根据对象的类型进行绑定.

后期绑定也称为动态绑定或者运行时绑定,Java中除了static方法和final方法外,其他所有的方法都是后期绑定.意味着无需判定是否进行后期绑定--因为会自动发生.

可拓展性

回到开始的代码示例,由于有多态机制,所以可以根据自己的需要对系统添加任意多的新类型,而不需要改变tune方法中参数的引用类型.这样的程序就是可扩展的.

这就是面向基类和面向抽象编程的重要意义.

缺陷
直接访问域对象,这个访问在编译期就会进行解析

示例中,子父类拥有一样的成员变量

public class FieldTest {
    public int num =10;
    public int getNum() {
        return num;
    }
}
public class FieldSubTest extends FieldTest{
    public int num = 20;
    @Override
    public int getNum() {
        return num;
    }
    public int getSuper(){
        return super.num;
    }
}
public class TestMain {
    public static void main(String[] args) {
        FieldTest fieldTest = new FieldSubTest();
        System.out.println(fieldTest.num+"----"+fieldTest.getNum());
        FieldSubTest fieldSubTest = new FieldSubTest();
        System.out.println(fieldSubTest.num+"----"+fieldSubTest.getNum()+"----"+fieldSubTest.getSuper());
    }
}

运行结果

10----20
20----20----10

产生这样结果的原因就在于所有的域访问操作(直接访问public修饰的成员变量),将有编译期进行解析,因此不是多态的.

但是开发中一般不会这样操作,一般都会通过方法对变量进行访问.

如果方法是静态的,它的行为就不具有多态性.

静态方法是与类,而不是与单个对象相关联的.

协变返回类型

在JavaSE5.0开始,允许方法返回对象的基类.

其余特点与注意

多态还有不少需要注意的地方,例如向下转型,通过组合代替继承等,需要更加多编程经验才能真正掌握多态的意义和灵活使用的方法.

上一篇下一篇

猜你喜欢

热点阅读