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
创建s1
和s3
之间有什么区别?
请让我知道
在String中我们只有String对象,那么为什么它以不同的方式处理这两个。
s1和s2具有不同的存储器地址,而s3和s4具有相同的存储器地址。
为什么它基于 new
运算符。?
答案 0 :(得分:5)
当加载定义它们的类时,Java源代码中表示字符串文字的String
对象将添加到共享String
池中。这确保了String文字的所有“副本”实际上都是同一个对象......即使文字出现在多个类中。这就是为什么s3 == s4
是true
。
相反,当您new
一个String时,会创建一个不同的新String对象。这就是s1 == s2
为false
的原因。 (这是new
的基本属性。保证创建并返回一个新对象......如果它正常完成。)
但是,在任何一种情况下,字符串都会使用相同的字符,这就是equals
返回true
的原因。
虽然理解正在发生的事情很重要,但真正的课程是正确的比较Java字符串的方法是使用equals
而不是==
。
如果要安排使用==
测试String对象的相等性,可以使用String.intern
方法“实例化”它们。但是,你必须始终这样做......并且实习在各方面都是一个昂贵的过程......因此通常不是一个好主意。
答案 1 :(得分:3)
s1
是一个新的String对象,不属于任何池化实例的一部分。 s3
是来自池的字符串实例。查找 java String pool 。请查看String
上的相关intern()方法。
这个概念并不是java独有的。其他语言支持String interning。在该相关说明中,池化经常使用的对象遵循flyweight模式,并且不限于字符串。看看Integer.valueOf()
。整数也有自己的恒定池。
答案 2 :(得分:2)
JVM具有自动优化功能。除非您专门创建一个新的String
对象,并且另一个String
对象已经存在且具有相同的值,否则JVM
会自动认为新对象不是必需的,并且会为您分配一个指向已存在的相等String
对象的指针。
基本上,当你使用第二个选项时,会发生这种情况:
第1步
创建第一个对象没问题。
第2步
在创建第二个对象之前,将检查字符串池的值。
如果该值当前存在,则无需创建新对象。它只返回对String
对象的引用。
第3步
不是分配新的Object,而是简单地给出对步骤1中对象的引用。这是为了节省内存。
答案 3 :(得分:0)
这是因为new
运算符强制创建一个新的String实例,而在第二种情况下,因为String
是一个不可变类,JVM为你提供了相同的String实例变量来节省内存。因为其中一个这样的对象不会发生变化而导致第二个变化(不可变,记得吗?)这是可以的。