我刚刚遇到了一些奇怪的行为,我不希望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
答案 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)
你必须注意两点:
"Two"
被实现了,这个文本的所有出现都将引用同一个实例。List.indexOf()
不会通过==
(即对象标识)比较项目,而是使用equals()
- 这是一种类定义的方法来比较两个对象的相等性(这使得完美的感觉,否则你将无法在列表中找到某些东西,除非你已经有了它的参考)。因此,即使两个不同的String
- 对象(例如由new String("Two")
创建)仍然会产生相同的输出。为了完整性,来自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;)。如果有一个框架允许你指定一个特定的方法确实是一个函数(或者他们称之为纯粹的),然后让分析器确保你没有意外地引入一个突变,那将是很好的。受该注释保护的代码。