手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>程序设计>Java技术>列表

在Java编程中的继承多数是有害的?原因

来源:互联网 作者:west263.com 时间:2008-02-23
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!

让我们一起检查脆弱的基类和基类耦合的问题。下面的类extends了Java的ArrayList类去使它像一个stack来运转:

 class Stack extends ArrayList
  {
  private int stack_pointer = 0;
  public void push( Object article )
  {
  add( stack_pointer , article );
  }
  public Object pop()
  {
  return remove( --stack_pointer );
  }
  public void push_many( Object[] articles )
  {
  for( int i = 0; i < articles.length; i )
   push( articles[i] );
  }
  }

甚至一个象这样简单的类也有问题。思考当一个用户平衡继承和用ArrayList的clear()方法去弹出堆栈时:

Stack a_stack = new Stack();
  a_stack.push("1");
  a_stack.push("2");
  a_stack.clear();

这个代码成功编译,但是因为基类不知道关于stack指针堆栈的情况,这个stack对象当前在一个未定义的状态。下一个对于push()调用把新的项放入索引2的位置。(stack_pointer的当前值),所以stack有效地有三个元素-下边两个是垃圾。(Java的stack类正是有这个问题,不要用它).

对这个令人讨厌的继承的方法问题的解决办法是为Stack覆盖所有的ArrayList方法,那能够修改数组的状态,所以覆盖正确的操作Stack指针或者抛出一个例外。(removeRange()方法对于抛出一个例外一个好的候选方法)。

这个方法有两个缺点。第一,如果你覆盖了所有的东西,这个基类应该真正的是一个interface,而不是一个class。如果你不用任何继承方法,在实现继承中就没有这一点。第二,更重要的是,你不能够让一个stack支持所有的ArrayList方法。例如,令人烦恼的removeRange()没有什么作用。唯一实现无用方法的合理的途径是使它抛出一个例外,因为它应该永远不被调用。这个方法有效的把编译错误成为运行错误。不好的方法是,如果方法只是不被定义,编译器会输出一个方法未找到的错误。如果方法存在,但是抛出一个例外,你只有在程序真正的运行时,你才能够发现调用错误。

对于这个基类问题的一个更好的解决办法是封装数据结构代替用继承。这是新的和改进的Stack的版本:

class Stack
  {
  private int stack_pointer = 0;
  private ArrayList the_data = new ArrayList();
  public void push( Object article )
  {
  the_data.add( stack_poniter , article );
  }
  public Object pop()
  {
  return the_data.remove( --stack_pointer );
  }
  public void push_many( Object[] articles )
  {
  for( int i = 0; i < o.length; i )
   push( articles[i] );
  }
  }

到现在为止,一直都不错,但是考虑脆弱的基类问题,我们说你想要在stack创建一个变量, 用它在一段周期内跟踪最大的堆栈尺寸。一个可能的实现也许象下面这样:

class Monitorable_stack extends Stack
  {
  private int high_water_mark = 0;
  private int current_size;
  public void push( Object article )
  {
  if( current_size > high_water_mark )
   high_water_mark = current_size;
   super.push( article );
  }
  publish Object pop()
  {
  --current_size;
  return super.pop();
  }
  public int maximum_size_so_far()
  {
  return high_water_mark;
  }
  }

这个新类运行的很好,至少是一段时间。不幸的是,这个代码发掘了一个事实,push_many()通过调用push()来运行。首先,这个细节看起来不是一个坏的选择。它简化了代码,并且你能够得到push()的派生类版本,甚至当Monitorable_stack通过Stack的参考来访问的时候,以至于high_water_mark能够正确的更新。

关键词:
【推荐给好友】【关闭】
最新五条评论
查看全部评论
评论总数 0 条
您的评论
用户名: 新注册) 密 码: 匿名:
·用户发表意见仅代表其个人意见,并且承担一切因发表内容引起的纠纷和责任
·本站管理人员有权在不通知用户的情况下删除不符合规定的评论信息或留做证据
·请客观的评价您所看到的资讯,提倡就事论事,杜绝漫骂和人身攻击等不文明行为

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!