为什么List接口的lastIndexOf()方法接受Object作为参数而不是E?

时间:2012-01-31 07:38:05

标签: java list generics

List接口的lastIndexOf()方法接受一个Object类型的参数。

但是,add()方法接受E类型的参数(这是在创建List时定义的List的泛型类型) 由于add()只接受E,因此可以防止开发人员(或用户)在编译时自行将任何不兼容的对象添加到列表中。

现在,Java doc说如果传递的对象不兼容,lastIndexOf()可以抛出ClassCastException。但是,当我在Eclipse Helios中运行以下代码时,我没有得到任何异常: -

package scjp.collection.list;

import java.util.ArrayList;
import java.util.List;

public class LastIndexOf {
public static void main(String[] args) {
    List<String> list = new ArrayList<String>();

    list.add("some");
    list.add("thing");
    list.add("at");
    list.add("last");
    list.add("and");
    list.add("at");
    list.add("again");



    System.out.println(list.lastIndexOf("at"));
    System.out.println(list.lastIndexOf(10));                    // # 1
    System.out.println(list.lastIndexOf(new LastIndexOf()));     // # 2
}
}

在第1行和第2行,我将不兼容的对象传递给我的List类型为String。 但是,我得到的输出是: -

5
-1
-1

我没有得到ClassCastException。

如果lastIndexOf()方法接受了E类型的对象而不是Object类型的对象,那么这只能在编译时被阻止。为什么不这样做?

Java创建者必须考虑到如果接受E(而不是Object)可能会出现的问题。会有什么害处?

6 个答案:

答案 0 :(得分:2)

您不需要E类型 - 请记住,对于演员表而言,泛型只是经过类型检查的糖,并且equals上定义了Object,因此您不需要投射项目以确定它是否等于列表中的其他项目。另外,请考虑有界通配符用法。如果您的列表定义为List<? extends Foo>,那么lastIndexOf以外的任何项目都无法获得null

答案 1 :(得分:2)

出于与Collection.remove(Object o)具有相似签名的相同原因。有关详细信息,请参阅this question

答案 2 :(得分:2)

在方法中,如remove,它将遍历Array [E]并在每个对象上尝试equals()方法,然后在找到时通过索引删除。 lastIndexOf与以下内容相同。

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

因此,如果LastIndexOf类定义了自己的equals函数,并且使其等于字符串“at”,那么根据java规范,lastIndexOf(new LastIndexOf())应该将值返回为lastIndexOf("at")。< / p>

另请查看此处。 Why aren't Java Collections remove methods generic? 另一个 What are the reasons why Map.get(Object key) is not (fully) generic

答案 3 :(得分:1)

这是一个可能有帮助的例子。请注意,equals使用的ArrayList<T>方法如果以相同的顺序传递具有相同元素的LinkedList<T>,则返回true。因此,如果您有List<ArrayList<Integer>>,则可以在其上调用lastIndexOf,传递LinkedList<Integer>,以便找到相等的ArrayList<Integer>。但如果以您描述的方式定义lastIndexOf,则无法做到这一点。

答案 4 :(得分:0)

lastIndexOf只关心equals()方法。所以它很乐意接受任何事情,并且只有在底层的equals()方法确实存在时才会爆炸。

更安全的一种方法就是定义一个“可以检查是否相等”的接口,这有点像Comparable。但这是很多工作方式而不是向后兼容。

答案 5 :(得分:-1)

考虑它的一种可能方式是因为泛型中的通配符。

想象一下,如果你有,

List<? extends Serializable> list = new ArrayList<> extends Serializable>();

(假设所有字符串都在list)。如果列表API有List.lastIndexOf(E e),那么从字面上看,通过上面的示例,这会使它成为List.lastIndexOf(? extends Serializable),并且您无法真正传递null以外的对象。

这就是他们将Object作为参数类型的原因。应该只为equals()搜索正确实现对象的lastIndexOf()方法。