分配并创建新的字符串差异

String s1 = new String("string"); String s2 = new String("string"); String s3 = "string"; String s4 = "string"; System.out.println(s1 == s2); //FALSE System.out.println(s2.equals(s1)); //TRUE System.out.println(s3 == s4); //TRUE System.out.println(s3.equals(s4)); //TRUE 

创建s1s3什么区别 ? 请告诉我

在String中我们只有String对象,那么为什么它以不同的方式处理这两个。 s1和s2具有不同的存储器地址,而s3和s4具有相同的存储器地址。 为什么它基于new运营商。

在加载定义它们的类时,Java源代码中表示字符串文字的String对象将添加到共享String池中。 这确保了String文字的所有“副本”实际上都是同一个对象…即使文字出现在多个类中。 这就是s3 == s4true

相反,当您new一个String时,会创建一个不同的新String对象。 这就是为什么s1 == s2false 。 (这是new的基本属性。保证创建并返回一个新对象……如果它正常完成。)

但是,在任何一种情况下,字符串都将具有相同的字符,这就是为什么equals返回true


虽然理解正在发生的事情很重要,但真正的教训是比较Java字符串的正确方法是使用equals而不是==

如果要安排使用==可以测试String对象的相等性,可以使用String.intern方法“实例化”它们。 但是,你必须始终这样做……并且实习在各方面都是一个昂贵的过程…所以这通常不是一个好主意。

s1是一个新的String对象,它不属于任何池化实例的一部分。 s3是来自池的字符串的实例。 查找java String池 。 看看String上的相关intern()方法。

这个概念并不是java独有的。 其他语言支持字符串实习 。 在该相关注释中,池化经常使用的对象遵循flyweight模式,并且不限于字符串。 看一下Integer.valueOf() 。 整数也有自己的恒定池。

JVM具有自动优化function。 除非您专门创建一个新的String对象,并且另一个String对象已经存在且具有相同的值,否则JVM自动假定新对象不是必需的,并且将为您指定一个指向已存在的相等String对象的指针。

基本上,当您使用第二个选项时,会发生以下情况:

步骤1

第一个对象创建没问题。

第2步

在创建第二个对象之前,将检查字符串池的值。 如果该值当前存在,则无需创建新对象。 它只返回String对象的引用。

第3步

它不是被赋予一个新的Object,而是简单地给出了对步骤1中所做对象的引用。这是为了节省内存。

发生这种情况是因为new运算符强制创建String的新实例,而在第二种情况下,由于String是不可变类,JVM为两个变量提供相同的String实例以节省内存。 因为其中一个这样的对象不会发生变化而导致第二个变化(不可变,记得吗?)这是可以的。