扩展ArrayList - 脆弱基类

时间:2017-06-28 01:07:30

标签: java stack stack-pointer

检查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()添加到堆栈中,然后我们想要使用基类-ie ArrayList的clear()清除堆栈 -

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

代码成功编译,但由于基类不知道   关于堆栈指针的任何事情,Stack对象现在都在   未定义的状态。下一次调用push()会将新项目放在索引2处   (stack_pointer&#39;当前值),因此堆栈有效   它上面有三个元素 - 底部两个是垃圾。

所以我的问题是,为什么

  

基类对堆栈指针

一无所知

换句话说,堆栈指针的状态在哪里被保留?

来源:Why extends is evil

2 个答案:

答案 0 :(得分:3)

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

您需要覆盖clear()课程中的Stack方法。

这样的东西
@Override
public void clear()
{
   super.clear();
   stack_pointer = 0;
}

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

此外,您需要注意,用户可以调用add()上的insert()Stack等函数,因为它们未被覆盖,因此会调用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;
    }
}

答案 1 :(得分:0)

以下是其中一种方式:

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