为什么ArrayList的indexOf方法有效?

时间:2014-08-15 08:42:21

标签: java arraylist indexof

请考虑以下代码(非常简单)

public class Main {

    public static class A{
        int id;

        public A(final int id){
            this.id = id;
        }

        @Override
        public boolean equals(final Object obj) {
            if(obj instanceof A){
                final A a = (A) obj;
                return id == a.id;
            }
            return false;
        }
    }

    public static void main(final String[] args) {
        final List<A> items = new ArrayList<A>();
        items.add(new A(0));
        items.add(new A(1));

        final Object obj = new A(1);
        System.out.println(items.indexOf(obj));
    }
}

当我运行此代码时,将在控制台中记录1。在我看来,它不应该是1,而应该是-1。我已查看了indexOf source code。从那里完全复制/粘贴:

public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

正如我们所知,当我的代码想要运行时,上述代码的else段开始执行。正如您在那里看到的,语句o.equals(elementData[i])将被执行。到目前为止一切都还可以,我没有问题

我的问题

上述方法中变量o的类型为Object,当我们调用它的equals方法时,我认为通用对象的equals方法将被执行,另一方面,我查看了对象source codeequals方法。我在这里复制/粘贴它:

public boolean equals(Object obj) {
    return (this == obj);
}

现在,在indexOf方法的for循环中,它不应该与o对象匹配任何项,因为数组中没有项等于{{1 } {object},o观点

现在我想知道我的代码输出是如何等于==的。任何人都可以帮助我吗?

由于

4 个答案:

答案 0 :(得分:8)

obj静态类型为Object,但运行时类型为A

由于Java中的所有方法都是virtual,因此静态类型并不重要。它是将确定调用哪个方法的被调用者的运行时类型。在这种情况下,运行时类型为A,因此调用A.equals

类似下面的代码段会调用String.toString而非Object.toString,因为o的运行时类型为String

Object o = "Hello";
System.out.println(o.toString());

// Prints "Hello" and not something like "java.lang.String@15db9742"

答案 1 :(得分:6)

您将变量的编译时类型与其值的执行时间类型混淆。

由于覆盖,将调用A.equals方法而不是Object.equals - 执行时间类型用于确定使用哪种方法覆盖。如果不是这种情况,ArrayList.indexOf 永远不会永远使用自定义相等覆盖。不要忘记obj代码完全不知道ArrayList.indexOf的声明类型。它只有o参数的 - 它是对A实例的引用。

区分编译时类型(用于重载,检查可用成员等)和执行时的值(用于覆盖,instanceof等)非常重要。 / p>

答案 2 :(得分:1)

你的错误在这里:&#34;在我看来,等于通用对象的方法将被执行,&#34;。虽然指定的类型&#34; o&#34;是&#34;对象&#34;,它仍然具有&#34; A&#34;的实际类型。意思是,o.equals(...)实际上会调用A.equals,而不是Object.equals。

答案 3 :(得分:0)

A扩展Object,您已覆盖其equals(Object)方法。因此,通过Object引用,您会看到它从Object继承的方法,但是调用它会调用您提供的equals方法。

只有当您的equals(Object)方法调用super.equals(Object)时才会发生您所声称的内容。

如果情况并非如此,那么异类收集和继承将毫无用处,OOP将会耗尽。