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)可能会出现的问题。会有什么害处?
答案 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()
方法。