网站首页
JSP空间
动态资讯
开源项目
技术文档
资源下载
J2EE资源
客户论坛
在线支付
 
  技术文档>>JAVA>>新手入门>>基础入门>查看文档  
  产生正确的行为     
  文章作者:未知  文章来源:水木森林  
  查看:69次  录入:管理员--2007-11-17  
 


  知道java里绑定的所有方法都通过后期绑定具有多形性以后,就可以相应地编写自己的代码,令其与基础类沟通。此时,所有的衍生类都保证能用相同的代码正常地工作。或者换用另一种方法,我们可以“将一条消息发给一个对象,让对象自行判断要做什么事情。”
  
  在面向对象的程序设计中,有一个经典的“形状”例子。由于它很容易用可视化的形式表现出来,所以经常都用它说明问题。但很不幸的是,它可能误导初学者认为oop只是为图形化编程设计的,这种认识当然是错误的。
  
  形状例子有一个基础类,名为shape;另外还有大量衍生类型:circle(圆形),square(方形),triangle(三角形)等等。大家之所以喜欢这个例子,因为很容易理解“圆属于形状的一种类型”等概念。下面这幅继承图向我们展示了它们的关系:
  
产生正确的行为

  上溯造型可用下面这个语句简单地表现出来:
  
  shape s = new circle();
  
  在这里,我们创建了circle对象,并将结果句柄立即赋给一个shape。这表面看起来似乎属于错误操作(将一种类型分配给另一个),但实际是完全可行的——因为按照继承关系,circle属于shape的一种。因此编译器认可上述语句,不会向我们提示一条出错消息。
  
  当我们调用其中一个基础类方法时(已在衍生类里覆盖):
  
  s.draw();
  
  同样地,大家也许认为会调用shape的draw(),因为这毕竟是一个shape句柄。那么编译器怎样才能知道该做其他任何事情呢?但此时实际调用的是circle.draw(),因为后期绑定已经介入(多形性)。
  
  下面这个例子从一个稍微不同的角度说明了问题:
  
  //: shapes.java
  // polymorphism in java
  
  class shape {
   void draw() {}
   void erase() {}
  }
  
  class circle extends shape {
   void draw() {
  system.out.println("circle.draw()");
   }
   void erase() {
  system.out.println("circle.erase()");
   }
  }
  
  class square extends shape {
   void draw() {
  system.out.println("square.draw()");
   }
   void erase() {
  system.out.println("square.erase()");
   }
  }
  
  class triangle extends shape {
   void draw() {
  system.out.println("triangle.draw()");
   }
   void erase() {
  system.out.println("triangle.erase()");
   }
  }
  
  public class shapes {
   public static shape randshape() {
  switch((int)(math.random() * 3)) {
   default: // to quiet the compiler
   case 0: return new circle();
   case 1: return new square();
   case 2: return new triangle();
  }
   }
   public static void main(string[] args) {
  shape[] s = new shape[9];
  // fill up the array with shapes:
  for(int i = 0; i < s.length; i++)
   s[i] = randshape();
  // make polymorphic method calls:
  for(int i = 0; i < s.length; i++)
   s[i].draw();
   }
  } ///:~
  
  针对从shape衍生出来的所有东西,shape建立了一个通用接口——也就是说,所有(几何)形状都可以描绘和删除。衍生类覆盖了这些定义,为每种特殊类型的几何形状都提供了独一无二的行为。
  
  在主类shapes里,包含了一个static方法,名为randshape()。它的作用是在每次调用它时为某个随机选择的shape对象生成一个句柄。请注意上溯造型是在每个return语句里发生的。这个语句取得指向一个circle,square或者triangle的句柄,并将其作为返回类型shape发给方法。所以无论什么时候调用这个方法,就绝对没机会了解它的具体类型到底是什么,因为肯定会获得一个单纯的shape句柄。
  
  main()包含了shape句柄的一个数组,其中的数据通过对randshape()的调用填入。在这个时候,我们知道自己拥有shape,但不知除此之外任何具体的情况(编译器同样不知)。然而,当我们在这个数组里步进,并为每个元素调用draw()的时候,与各类型有关的正确行为会魔术般地发生,就象下面这个输出示例展示的那样:
  
  circle.draw()
  triangle.draw()
  circle.draw()
  circle.draw()
  circle.draw()
  square.draw()
  triangle.draw()
  square.draw()
  square.draw()
  
  当然,由于几何形状是每次随机选择的,所以每次运行都可能有不同的结果。之所以要突出形状的随机选择,是为了让大家深刻体会这一点:为了在编译的时候发出正确的调用,编译器毋需获得任何特殊的情报。对draw()的所有调用都是通过动态绑定进行的。
 
 
上一篇: 多形性扩展性    下一篇: 为什么要上溯造型
  相关文档
核心api最佳实践——jdk日志分级 11-17
j2ee基础篇 对log4j使用方法的简单讲解 11-16
java中的排序 11-17
一些面向对象的设计法则(3) 11-17
使用 java reflection 11-16
struts框架 11-17
开始你的第一个struts应用程序 11-17
oracle与php实例开发myers订单跟踪系统 09-11
java实现利用搜索引擎收集网址的程序 11-16
j2me中使用缓存将屏幕内容存储为image 11-16
weblogic6.0使用心得 11-17
java编程思想(完整的中文简体第二版) 11-17
面向对象-java对象序列化 11-17
ejb 异常处理的最佳做法(2) 11-17
用rmi进行远程方法调用 11-16
敏捷开发的必要技巧:慎用继承 11-17
问题解决分析:stringbuffer的小问题 11-17
java基础:用java代码构建一个线程池 12-05
java入门--eclipse,j2ee入门学习心得 01-22
深入浅出java模式设计之模板方法模式 11-16
返回首页 | 关于我们 | J网章程 | JSP空间合租 | 客服中心 | 免责声明 | 常见问题 | 参观机房
本站主机空间代理至厦门市华众网络科技有限公司
《中华人民共和国增值电信业务经营许可证》
编号:闽B2-20050079
@2005-2008福建JSP技术网 版权所有 闽ICP备05000928号
厦门(总部):13616026886 福州:0591-87655121
邮箱:admin@fjjsp.com 站长QQ,点击这里给我发消息