将一个方法调用同一方法主体关联进来就叫做绑定。如果在程序执行前进行绑定由编译器和连接程序实现,叫做前期绑定。这个是在面向过程的语言中不需要选择就默认的绑定方式。现在我对面各过程语言已经很模糊了,高中是只知道面向过程依稀记得那时用的好像是什么Fox或Fox什么的。

在运行时根据对象的类型进行绑定,叫做后期绑定也称动态绑定或运行时绑定。如果一种语言想实现后期绑定,,就必须具有某种机制,以便在运行时能判断对象的类型,从面调用恰当的方法。也就是说编译器一直不知道对象的类型,但是方法调用机制能找到正确的方法体,产加以调用。后期绑定机制随语言的不同而有所不同,介是只要想一下就会得知,不管怎样都必须在对象中安置某种“类型信息”。

Java中除了static和final方法(private方法属于final方法)之外,其他所有方法都是后期绑定。所以java中所有方法都是通过动态绑定实现多态的,所以就可以编写只与基类打交道的程序代码了,并且这些代码对所有的导出类都可以正确运行。或者说是发送消息给某个对象,让该对象去断定应该做什么事。

上例子说话:

package com.ebao.java.dynamic.binding;

public class Shape {
 public void draw(){}
 public void erase(){}
}

 

public class Circle extends Shape {
 public void draw(){
  System.out.println("========Circle.draw()==");
 }
 public void erase(){
  System.out.println("========Circle.erase()==");
 }
}

 

public class Square extends Shape {
 public void draw(){
  System.out.println("========Square.draw()==");
 }
 public void erase(){
  System.out.println("========Square.erase()==");
 }
}

 

public class Trangle extends Shape {
 public void draw(){
  System.out.println("========Trangle.draw()==");
 }
 public void erase(){
  System.out.println("========Trangle.erase()==");
 }
}

 

import java.util.Random;

public class RandomShapeGenerator {
 private Random ran = new Random(47);
 public Shape next(){
  switch(ran.nextInt(3)){
   default:
   case 0:return new Circle();
   case 1:return new Square();
   case 2:return new Trangle();
  }
 }
}

 

public class TestShape {
 private static RandomShapeGenerator gen = new RandomShapeGenerator();
 public static void main(String[] args){
  Shape[] s = new Shape[9];
  for(int i=0;i<s.length;i++){
   s[i] = gen.next();
  }
  for(Shape shp:s)
   shp.draw();
 }
}

运行结果:

========Trangle.draw()==
========Trangle.draw()==
========Square.draw()==
========Trangle.draw()==
========Square.draw()==
========Trangle.draw()==
========Square.draw()==
========Trangle.draw()==
========Circle.draw()==

RandomShapeGenerator是一种“工厂”(factory),在每次调用next()方法时,它可以为随机选择的Shape对象产生一引用。请注意向上转型是在return语句里发生的。每个return语句取得一个指向某个Circle、Square、Triangle的引用,并将其以Shape类型从next()方法中发送出去。所以无论什么调用next()方法时,是绝对不可能知道具体类型到底是什么的。因为我们总是只能获得一通用的Shape引用。所以随机选择很好的说明了,在编译时,编译器不需要获得任何特殊信息就能进行正确的调用。对draw()方法的所有调用都是通过动态绑定进行的。

 

示例二: 创建一个包含两个方法的基类。在第一个方法中可以调用第二个方法。然后产生一个继承自该类的导出类,且覆盖基类中的第二个方法。为该导出类创建一个对象,将其向上转型到基类开并调用第一个方法。

package com.ebao.java.dynamic.binding;

public class Shape1 {
 public void draw(){
  System.out.println("-------------------Shape1.draw()");
  this.erase();
 }
 public void erase(){
  System.out.println("-------------------Shape1.erase()");
 }
}

 

public class TestShape1 extends Shape1 {
 public void erase(){
  System.out.println("-------------------TestShape1.erase()");
 }
 public static void main(String[] args){
  Shape1 s1 = new TestShape1();
  s1.draw();
 }
}

运行结果:

-------------------Shape1.draw()
-------------------TestShape1.erase()

由此可看出向上转型后的引用不管调用的方法有没有被导出类覆盖,整个过程中只要涉及到的方法被导出类覆盖了,动态绑定的就是导出类的方法。

posted on 2015-08-31 11:57  幸运叶  阅读(239)  评论(0编辑  收藏  举报