为什么List.contains()将Object作为Collections Java中的参数 [英] Why List.contains() takes Object as an argument in Collections Java

查看:197
本文介绍了为什么List.contains()将Object作为Collections Java中的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

java.util.List.contains(Object o)方法将Object作为参数,并在内部使用Object.equals(Object o),如

The java.util.List.contains(Object o) method takes Object as an argument and internally uses Object.equals(Object o) as described here.

如果我在Netbeans中执行以下代码:

If I do the following code in Netbeans:

 List<String> listStr = new ArrayList<>();
 listStr.contains(34); //warning

它给出明显警告,即:

Given object can not contain instances of int (expected String)

因为所有人都可以看到,所以String永远不会等于int,那么为什么不应该将元素类型 E(在我的情况下为String)作为参数而不是Object?

Since it visible to all, that String never be equal to int then why shouldn't it take Element type E (in my case String) as an argument instead of Object?

推荐答案

严格来说,这样的实现是错误的.

Strictly speaking such an implementation would be wrong.

这样做的原因是,即使对象不是E类型,它仍然可以在equals()调用中返回true.

The reason for this is that even if an object is not of type E, it could still return true on an equals() call.

假设一秒钟,您有一个像这样的课程:

Assume for a second, that you've got a class like this:

public class FakeString {
  private final String value;

  public FakeString(String value) {
    if (value == null) {
      throw new IllegalArgumentException();
    }
    this.value = value;
  }

  public int hashCode() {
    return value.hashCode();
  }

  public boolean equals(Object o) {
    return value.equals(o);
  }
}

然后此代码将打印true:

List<String> strings = Arrays.asList("foo", "bar", "baz");
System.out.println(strings.contains(new FakeString("bar")));

为了澄清:此行为是预期的,并且是contains()采用Object而不是E的原因.顺便说一句,remove()也是这样.

And just to clarify: this behaviour is intended and is the reason why contains() takes an Object instead of E. The same is true for remove(), by the way.


您的int将被装箱到Object.

(int) === boxing ===> (Integer) ==== reference widening ===> (Object)

但是Netbeans很聪明,可以检测到这一点,请注意您的IntegerString不兼容.通常,这将引发ClassCastException.但是,javadoc明确指出在

But Netbeans is smart and detects this, notices that your Integer is incompatible with a String. Normally this would throw a ClassCastException. However, the javadoc clearly states that throwing the ClassCastException on Collections.contains(Object) is optional.

因此,在这种情况下,重载contains方法以允许Element类型没有好处,因为intfloatdouble等可以成功地自动装箱到Object.因此,仅Objectcontains就可以了.

So in this case, there would be no benefit to overload the contains method to allow an Element type because int, float, double, etc can be autoboxed to Object successfully. Therefore, a contains with just Object is just fine.


由于未知原因,如果 "f所指定元素的类型与此不兼容,则ListHashSetSetLinkedHashSet不会抛出ClassCastException.在此处插入类型](可选)" .请注意 可选 部分.如您所示,当您尝试传递不兼容的类型时,Netbeans会给您一个可疑的警告.如果您尝试使用逻辑来依赖.contains(...)的返回值,那么这里就是陷阱.不注意警告的开发人员可能会陷入这样的陷阱,即假设contains将始终 工作 ,但事实并非如此.

For reasons unknown, List, HashSet, Set, and LinkedHashSet do not throw a ClassCastException if "f the type of the specified element is incompatible with this [insert type here] (optional)". Note the optional part. As you have shown, Netbeans will give you a suspicious warning when you try to pass an incompatible type. The trap here is if you try to use logic to rely on the return value of .contains(...). A developer who doesn't pay attention to his warnings could fall into the trap of assuming that contains will always work, but then it doesn't.

作为此博客的开发人员建议,请采取以下四个步骤来避免将来出现这种陷阱:

As the developer at this blog recommends, here are four steps to avoid this pitfall in the future:

  1. 谨慎的编码和代码审查可能导致开发人员或审查者看到不相关的类的对象正在传递 到contains方法.我通常不舒服 只是这种形式的保护.

  1. Careful coding and code reviews might lead to developers or reviewers seeing that an object of an irrelevant class is being passed to the contains method. I'm typically uncomfortable leaving it with just this form of protection.

使用现代版本的NetBeans或标记可疑"行为的类似工具会很有帮助.

Use of a modern version of NetBeans or of similar tools that flag the "suspicious" behavior can be very helpful.

单元测试与代码覆盖率测试相结合,有助于通过代码识别可能看似奇怪的流,从而有助于 归因于诸如本文中所述的问题.

Unit tests combined with code coverage tests can be helpful in identifying seemingly strange flows through the code that can be attributed to issues such as the one described in this post.

Collection实现至少提供了运行时错误,以使开发人员知道不正确的行为. 正在采取行动.它可能不如编译时有效 检测,但确实可以更轻松地识别是否存在 问题及其发生的时间,然后再没有问题.但是,那 这种方法的主要缺点是选择哪种 集合实现的使用通常是由重要因素驱动的 经常超过运行时需求的考虑因素 检测到对contains的错误调用.

Collection implementations that do throw ClassCastException at least provide a runtime error to let developers know that an improper action is being taken. It may not be as effective as compile-time detection, but it does make it much easier to identify that there is a problem and what it is when it happens then without it. However, the major disadvantage with this approach is that the choice of which collection implementation to use is often driven by important considerations that often outweigh the desire to have runtime detection of an errant call to contains.

这篇关于为什么List.contains()将Object作为Collections Java中的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆