【问题标题】:Extending an ArrayList - fragile-base class扩展 ArrayList - 易碎基类
【发布时间】:2017-06-28 01:07:30
【问题描述】:

检查 Java 中的最佳实践,我们发现避免继承是一种很好的做法。原因之一可能体现在以下问题中:

这里我们有一个子类“Stack”扩展了“ArrayList”

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] );
    }
}

假设我们要使用前面代码中定义的push() 添加到堆栈,然后我们想使用基类的clear() 清除堆栈-即ArrayList-

Stack a_stack = new Stack();
a_stack.push("1");
a_stack.push("2");
a_stack.clear();
  • 问题出在这里

代码编译成功,但由于基类不知道 关于堆栈指针的任何信息,Stack 对象现在位于 未定义的状态。对 push() 的下一次调用将新项目置于索引 2 (stack_pointer 的当前值),因此堆栈有效地具有 上面三个元素——下面两个是垃圾。

所以我的问题是,为什么

基类对堆栈指针一无所知

也就是说,栈指针被保留的状态在哪里?

来源:Why extends is evil

【问题讨论】:

  • 对于你的想法,你必须实现栈顶。此外,您还需要添加一些额外的项目,例如架构:LIFO、FIFO 等
  • "下一次调用 push() 将新项目放在索引 2" 不,它会导致 IndexOutOfBoundsException
  • "栈指针被保留的状态在哪里?" 对象数据,和ArrayList定义的所有其他数据一样,只是@987654329 @ 不知道,只有 Stack 知道。 --- 无论如何,你的代码有缺陷,因为不需要stack_pointer,因为列表大小是一样的。如果你想用ArrayList,那就用对了。如果你想要自己的stack_pointer(应该命名为stackPointer),那么不要使用ArrayList
  • 先生。 @Andreas 我在想别的东西。但是,“它会导致 IndexOutOfBoundsException”是什么意思,我猜它与此无关,这只是更新的 stack_pointer 变量的问题,在这种情况下 clear() 不会将其返回到 0。
  • add(int index, E element) 的 Javadoc 说:“如果索引超出范围(索引 size()),则抛出 IndexOutOfBoundsException。由于 index 为 2 且 size 为 0,所以你得到 ... IndexOutOfBoundsException.

标签: java stack stack-pointer


【解决方案1】:

变量stack_pointerStack 类的成员,那么ArrayList 超类怎么知道它呢?因为它不能也不会调用clear() 不会对它做任何事情。

您需要在 Stack 类中重写 clear() 方法。

类似

@Override
public void clear()
{
   super.clear();
   stack_pointer = 0;
}

然后当用户在Stack 上调用clear() 时,会导致指针被重置。

您还需要注意,用户可以在Stack 上调用函数add()insert() 等,因为它们未被覆盖,因此将调用ArrayList 函数。这可能不是您想要的。

更好的方法是创建一个Stack,其中包含一个ArrayList,这样您就可以隐藏需要隐藏的方法。

类似

public class Stack
{
    private ArrayList<Object> stack = new ArrayList<Object>();
    private int stack_pointer;

    public void push(Object obj)
    {
       stack.add(stack_pointer++, obj);
    }

    // Other methods

    public void clear()
    {
       stack.clear();
       stack_pointer = 0;
    }
}

【讨论】:

    【解决方案2】:

    这是其中一种方法:

    import java.util.ArrayList;
    
    class Stack extends ArrayList {
    
        private int stack_pointer = 0;
        private int stack_mem = 16;
        private ArrayList<Object> mem = new ArrayList<Object>();
    
        public void push(Object article) {
            if (stack_pointer < stack_mem) {
                mem.add(article);
                stack_pointer++;
            }
        }
    
        public Object pop() {
            if (stack_pointer > 0) {
                return mem.remove(stack_pointer--);
            }
            return null;
        }
    
        public void clear() {
            stack_pointer = 0;
            mem.clear();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-16
      • 2012-01-15
      • 1970-01-01
      • 2013-09-10
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多