重识Java多态
今天面试被问到了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开始,允许方法返回对象的基类.
其余特点与注意
多态还有不少需要注意的地方,例如向下转型,通过组合代替继承等,需要更加多编程经验才能真正掌握多态的意义和灵活使用的方法.