这个代码成功编译,但是因为基类不知道关于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能够正确的更新。
分享到:
相关推荐
大多数好的设计者象躲避瘟疫一样来避免使用实现继承(extends 关系)。实际上80%的代码应该完全用interfaces写,而不是通过extends。“JAVA设计模式”一书详细阐述了怎样用接口继承...这篇文章描述设计者为什么会这么作。
这篇文章描述设计者为什么会这么作。 Extends是有害的;也许对于Charles Manson这个级别的不是,但是足够糟糕的它应该在任何可能的时候被避开。“JAVA设计模式”一书花了很大的部分讨论用interface继承代替实现继承...
7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型标识 7.9 ...
7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...
7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...
在实际应用中,JAVA会将源代码转换为二进制的字节码,然后由不同的虚拟机(JVM)解释执行。这种方式使得JAVA程序能够轻松地适应不同的操作系统环境,而无需进行额外的修改或调整。 ##### 1. 执行能力与跨平台性 ...
7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...
7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...
7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...
总的来说,JRE6和`java.policy`文件在Java应用程序的安全管理中扮演了关键角色。理解和正确配置`java.policy`对于确保Java应用的安全性至关重要,同时也能帮助开发者在满足安全要求的同时实现功能需求。
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...
Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...