indexOf()具有重复字符串的奇怪Java.util.List行为

时间:2015-08-18 13:48:14

标签: java list

我刚刚遇到了一些奇怪的行为,我不希望Java中的ArrayList<String>。当然,这是因为我对Java中的引用的理解不足。

让我告诉你这段代码:

List<String> myList = new ArrayList<>();

myList.add("One");
myList.add("Two");
myList.add("Two");
myList.add("Three");

for (String s : myList){
  System.out.println(myList.indexOf(s));
}

这段代码提供以下输出:

0  
1  
1  
3

为什么?我故意添加了两个包含相同字符的字符串(&#34; Two&#34;),但对象本身不应该相同。我在这里误解了什么?我期待着其他输出:

0
1
2
3

4 个答案:

答案 0 :(得分:12)

ArrayList.indexOf()没有使用引用相等来查找对象。它使用equals()方法。注意文档说的内容(强调我的):

  

返回最低索引i,使得(o == null?get(i)== null: o.equals(get(i))),如果不存在,则返回-1索引。

因此,它将匹配逻辑上相等的第一个字符串。

修改

Andremoniy的评论绝对正确。在字符串文字的情况下,因为它们是实习的,所以它们也恰好具有相同的引用。因此,在这种情况下,您的2个字符串"Two"实际上是相同的引用。

System.out.println("Two" == "Two"); // will return true because they are the same reference.

答案 1 :(得分:2)

这只是因为indexOf会将列表中等于第一次次返回给定字符串。见其documentation

  

返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。更正式地,返回最低索引i,使(o==null ? get(i)==null : o.equals(get(i)))或-1,如果没有这样的索引。

答案 2 :(得分:1)

你必须注意两点:

  1. 很可能你正在使用相同的String-instance,因为常量"Two"被实现了,这个文本的所有出现都将引用同一个实例。
  2. List.indexOf()不会通过==(即对象标识)比较项目,而是使用equals() - 这是一种类定义的方法来比较两个对象的相等性(这使得完美的感觉,否则你将无法在列表中找到某些东西,除非你已经有了它的参考)。因此,即使两个不同的String - 对象(例如由new String("Two")创建)仍然会产生相同的输出。
  3. 为了完整性,来自indexOf的javadoc的引用(已在其他答案中提到:

      

    返回最低索引i,使得(o == null?get(i)== null:   o.equals(get(i))),如果没有这样的索引,则为-1。

答案 3 :(得分:0)

Java并不允许你区分这两者,但是你偶然发现了方法函数

简单地说一个方法可能会改变一个对象的状态。功能不会。因此,调用方法add(String)将更改List的状态。具体来说,它将String添加到列表中。 indexOf(String)然而,它不是一种方法,它是一种功能。现在可以肯定的是,Java称它们为方法,因为......这就是他们所谓的方法。并且可以想象,实施 - 可以 - 改变状态。但我们知道它不是合同。

一个函数,给定相同的输入(其中底层对象的当前状态是这些输入的一部分)将始终返回相同的结果。总是。这是一个关于功能的优点。您可以根据需要多次调用函数(一个真函数),只要输入和基础数据没有改变,就可以得到相同的结果。

麻省理工学院的一些人在Java中有research into the analysis个函数(为了避免混淆,他们称之为&#34;纯方法&#34;)。如果有一个框架允许你指定一个特定的方法确实是一个函数(或者他们称之为纯粹的),然后让分析器确保你没有意外地引入一个突变,那将是很好的。受该注释保护的代码。