我已经阅读了有关字符串实习的信息,其中字符串文字被重用,而使用new
创建的String对象没有被重用。当我打印true
和false
以确保它们相等时,可以在下面看到。具体来说,(p1==p2)!=p3
有两个对象,一个由p1
和p2
指向,另一个由p3
指向。但是,当我将它们添加到HashSet
时,都被认为是相同的。我期望a.size()
返回2
,但是它返回了1
。为什么会这样?
package collections;
import java.util.HashSet;
public class Col {
public static void main(String[] args) {
method1();
}
public static void method1()
{
HashSet a = new HashSet();
String p1 = "Person1";
String p2 = "Person1";
String p3 = new String("Person1");
if(p1 == p2)
System.out.println(true);
else
System.out.println(false);
if(p1 == p3)
System.out.println(true);
else
System.out.println(false);
a.add(p1);
a.add(p2);
a.add(p3);
System.out.println(a.size());
}
}
输出
true
false
1
答案 0 :(得分:0)
HashSet
使用 equality 保留一组唯一的值,而不是 identity (即,如果两个对象彼此equals
,但没有==
,HashSet
只会保留其中一个)。
您可以通过使用JDK的IdentityHashMap
和所有键之间共享的虚拟值来实现使用标识而不是相等的集合,类似于HashSet
基于HashMap
的方式
答案 1 :(得分:0)
我已经读过有关字符串实习的信息,在其中字符串的文字被重用,而使用new创建的String对象没有被重用。当我为它们的相等性打印真假时,可以在下面看到。具体来说,(p1 == p2)!= p3,所以有两个对象,一个由p1和p2指向,另一个由p3指向。但是,当我将它们添加到HashSet时,都被认为是相同的。我期望a.size()返回2,但它返回1。
仅当您使用==
比较String时,这是正确的,使用equals()
方法进行比较时结果是不同的。 (有疑问,您可以测试)。
当添加到HashSet
中时,使用的比较方法是equals()
作为对象的适当方法。因此,p1
,p2
和p3
是相等的。
您可以尝试使用equals()
进行测试,它将输出true
,true
,1
而不是true
,false
,{{1 }}
答案 2 :(得分:0)
p1和p2是字符串文字,由于字符串池的缘故,它们指向相同的值。因此,当我们使用==比较它们时,它们是匹配的。
p3是一个字符串对象,因此当我们使用==进行匹配时,它将尝试使用引用进行匹配,因此它给出false。
HashSet的add方法在内部调用HashMap的put方法。 HashMap的put方法使用hashCode和equals方法在HashMap中设置值。字符串实现hashCode和equals方法,并为相同的值提供相同的hashCode。 HashSet包含唯一值,因此它仅存储一个值。
答案 3 :(得分:0)
在这种情况下,我建议您学习如何使用javap
来理解您的代码是如何编译的,但让我尝试解释其背后的情况。
Java编译该类时,它将为该类创建用于构建所谓的常量池的指令。该常量池将保存对值为“ Person1” 的字符串的引用。编译后的逻辑还会说p1
,并且p2
的值应设置为对该字符串(它所驻留的内存中的地址)的常量池引用。调用p1==p2
将返回true
,因为它们在字面上具有相同的确切值。调用String p3 = new String("Person1");
时,您要告诉Java在内存中的另一个位置创建一个新字符串,该字符串只是原始字符串的副本,然后将p3
的值设置为对该位置的引用。新字符串对象所在的内存。因此,如果您调用p1 == p3
,它将返回false
,因为您所说的是“ p1
在内存中的位置是否等于p2
在内存中的位置?”
正如其他人指出的那样,如果您调用 希望这可以消除一些困惑!p1.equals(p3)
则会返回true
,因为.equals
会比较字符串值而不是引用强>。而且HashSet会看到所有相同的内容,因为它使用的方法.hashCode
与.equals
类似,因为它会生成 string值的哈希值。 / p>