集合API移除方法实现

问题描述 投票:0回答:1

我已经了解了 Java Collection API。 Collection接口定义了remove方法如下:

public interface Collection<E> {
    // other methods
    boolean add(E e);
    boolean remove(Object o);
}

您可以看到remove方法的参数是类型

Object
,而不是集合的元素类型
E
。我理解这个设计决策背后的逻辑:我更喜欢得到错误而不是
ClassCastException
。它还可以使客户端代码在调用此方法之前免于强制转换对象。 然而,奇怪的是某些集合实现了删除方法。以
ArrayList
实现为例:

public class ArrayList<E> extends AbstractList<E> {
    //Partial listing
    
    public boolean remove(Object o) {
        final Object[] es = elementData;
        final int size = this.size;
        int i = 0;
        found: {
            if (o == null) {
                for (; i < size; i++)
                    if (es[i] == null)
                        break found;
            } else {
                for (; i < size; i++)
                    if (o.equals(es[i])) //heeeeeeeeer!!!!!!!!!
                        break found;
            }
            return false;
        }
        fastRemove(es, i);
        return true;
    }
}

这里,实现调用外部对象

o
上的 equals 方法,而不是“可信”集合元素上的 equals 方法。对集合的元素调用 equals 方法(
es[i].equals(o)
)不是更安全吗?例如,如果
o
是一些不遵守 equals 契约的恶意对象,则删除方法可能会从集合中删除随机元素:

class MalObject {
    @Override
    public boolean equals(Object o) {
      return true;
    }
}

使用当前的删除实现,调用

list.remove(malObject)
会随机从列表中删除元素。

我看不出有任何明显的理由为什么不对集合元素调用 e

equals
方法。这个实施背后的原因是什么,背后有什么好处吗?

java arraylist collections
1个回答
0
投票

想象一个

List<Shape>
包含一个
Circle
和一个
Square
,它们都有相同的面积。如果它们具有相同的面积,则
Shape.equals
方法返回 true。
Circle.equals
方法还检查半径和
Square
,即边长。现在,如果您调用
remove(square)
并且
remove
调用
es[i].equals(o)
,它可能会删除圆圈。通过调用子类
equals
方法,它确保它只删除正方形。

至于您担心的问题,要删除的对象

o
可能具有的唯一“恶意”代码是在程序员的控制之下,即编写调用
remove(o)
的代码的程序员。这不是真正的安全问题。

© www.soinside.com 2019 - 2024. All rights reserved.