今天,看了java编程思想以后,对多态又有了一些新的感悟,在这里和大家分享学习。
多态也称为动态绑定、后期绑定或运行时绑定。java中的所有方法都是通过动态绑定实现多态的。
可能有点迷糊,代码可能比较直观
package cn.bababa;
class Instrument{
public void play() {
System.out.println("instrument.play()");
}
}
class Wind extends Instrument{
public void play() {
System.out.println("wind.play()");
}
}
public class Music{
public static void tune(Instrument i) {
i.play();
}
public static void main(String[] args) {
Wind flute = new Wind();
tune(flute);
}
}
结果:wind.play()
如上图代码,tune方法,它接受一个Instrument引用,那么在这种情况下,编译器怎么才能知道这个Instrument引用指向的是Wind对象,而不是Brass对象或其他呢?
实际上,编译器无法得知,研究这个必须先说一个概念。
什么是绑定?
讲一个方法调用同一个方法主体关联起来被称为绑定。若在程序执行前进行绑定(由编译器实现)叫做前期绑定。而当编译器只有一个Instrument引用时,它无法知道究竟调用的的哪个方法才对。解决的方法就是后期绑定:就是在运行时根据对象的类型进行绑定。也就是说编译器使用不知道对象类型,但是方法调用机制能找到正确的方法体,并加以调用。
Java中除了static和final方法(private方法属于final方法)之外,其他的所有方法都是后期绑定。
上图可能有人会问,为什么不在main(主函数)中,直接写Instrument i = new Wind();i.play();其实结果是一样的,只是那样写比较直观(其实是书上这样写的)
例如:如果你直接访问某个域,这个访问就将在编译期进行解析,就像下面的示例所演示这样。
要颠覆你的三观了,我是被教育了,真的...很严肃
package cn.bababa;
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.field+", sup.getField() = "+sup.getField());
Sub sub = new Sub();
System.out.println("sub.field = "+sub.field+", sub.getField() = "+sub.getField()+", sub.getSuperField() = "+sub.getSuperField());
}
}
结果:
sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0
当Sub对象转型为Super引用时,任何域访问操作都将由编译器解析,因此不是多态。在本例中,为Super.field和Sub.field分配了不同的存储空间(就针对Super sup = new Sub()这一句来说,先生成了Sub对象,再将他的引用向上转型为Super对象)。这样,sub实际上包含两个称为field的域:它自己的和它从super处得到的。然而,在引用sub中的field时所产生的默认域并非super版本的field域。因此,为了得到super.field,必须显示地指明super.field。 如果某个方法是静态的,它的行为也不具有多态性。因为静态方法是与类相关联,而非与单个对象相关联。
域:你可以理解为变量(lz个人理解)
当你看到这里并且充分理解,恭喜你,又进步了一毫米,后面可能会陆续更新一些java基础的知识,和大家分享,楼主最近正在以龟速爬java编思,回头见!