在回答这个问题时:" Checking if an object is contained within a linkedlist",我意识到用户正在尝试将String参数传递给LinkedList类型的LinkedList的contains方法:
LinkedList<LinkedList> list = new LinkedList<LinkedList>();
list.contains("String");
这不会引发任何编译错误,因为&#39;包含&#39;方法接受java.lang.Object并允许将字符串值传递给它。
所以出于好奇,我想了解为什么选择这种方法来接受&#39;对象&#39;当它被限制为只接受列表类型时(就像添加一样)。是不是它打败了泛型的整个目的,即在编译时加强类型检查&#34;?
答案 0 :(得分:8)
假设您有一个由BankAccount
标识的AccountId
(两个都是类,不会扩展另一个)。
现在我们假设您有LinkedList<BankAccount> accounts;
,并希望查看是否有具有指定ID的帐户。
现在,AccountId.equals()
可以接受BankAccount
并将自己与帐户的ID进行比较。有了这个,你就可以调用accounts.contains(account_id)
,即使contains()
的参数的类型与集合的类型完全无关,它也会正常工作。
答案 1 :(得分:4)
contains方法的规范说:
当且仅当此集合包含至少一个元素e时,才返回true
(o==null ? e==null : o.equals(e))
[docs oracle] [1]
但是,它还说如果集合不允许null元素,它可能抛出NullPointerException
,如果指定元素的类型与此集合不兼容,它可能抛出ClassCastException
。这些标记为optional
。
此外,它还说:
Collections Framework接口中的许多方法都是根据equals方法
定义的
但:
不应将此规范解释为暗示使用非null参数o调用Collection.contains将导致为任何元素调用o.equals(e)e
因此,我的结论是,这是允许实现定义不同行为(例如接受空元素)和优化(例如,重写类的equals方法,以便您可以检查集合中是否包含元素)的某种黑客没有提及它。)
我将用一个例子来解释最新的内容:
public class A {
public void initialize() {
// Lots of code and heavy initialization
}
public String id;
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
return this.hashCode() == o.hashCode();
}
}
然后:
SomeCollection<A> collection = new SomeCollection<A>();
// Create an element and add it to the collection
A a = new A();
a.initialize(); // Heavy initialization
element.id = "abc";
collection.add(a);
// Check if the collection contains that element
// We create a second object with the same id, but we do not initialize it
A b = new A();
b.id = "abc";
// This works for many common collections (i.e. ArrayList and HashSet)
collection.contains(b);
实际上,有更多方法,例如indexOf(Object o)
和remove(Object o)
。所以我认为这不是为了兼容性,而是为了实现这种解决方案而设计的。
http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#contains(java.lang.Object)
答案 2 :(得分:3)
简单... LinkedList实际上是一个Object。
此外,
假设您有每个链接列表的地图:
由于contains()
将Object作为参数,因此您可以为CustomMapItem设置equals()
和hashcode()
方法,以便找到相应的LinkedList。
答案 3 :(得分:1)
首先,contains方法不会修改底层集合,因此它没有像add方法那样的严格要求。
更重要的是,包含对象相等的处理。它实际上在列表的元素上调用equals方法。似乎两个对象相等,它们至少需要相同的类型,但实际情况并非如此。这完全取决于你的equals方法的定义。
一个例子:
List<A> myList = new LinkedList<A>();
...
B b = new B();
myList.contains(b); //expected true if 'value' attribute is equal.
class A {
int value;
public boolean equals(Object object){
if(object instanceof A && ((A)object).getValue() == this.value)
return true;
else if(object instanceof B && ((B)object).getValue() == this.value)
return true;
else
return false;
}
同样
class B {
int value;
public boolean equals(Object object){
if(object instanceof A && ((A)object).getValue() == this.value)
return true;
else if(object instanceof B && ((B)object).getValue() == this.value)
return true;
else
return false;
}
答案 4 :(得分:-1)
只是为了向后兼容。尽管泛型可用于将集合的内容限制为同类型,但如果您愿意,使集合包含异构对象仍然是一个有效的用例。
public static void main(String[] args)
{
List<String> homogeneousStringList = new ArrayList<String>();
homogeneousStringList.add("Foo");
homogeneousStringList.add("Bar");
List heterogeneousObjectList = new ArrayList();
heterogeneousObjectList.add("Foo");
heterogeneousObjectList.add(Integer.valueOf(1));
heterogeneousObjectList.add(new Date());
System.out.println(homogeneousStringList.toString());
System.out.println(heterogeneousObjectList.toString());
}
产生以下输出:
[Foo,Bar]
[Foo,1,Sun Sep 21 00:36:59 MDT 2014]