字符串a ==字符串b 的规则
我试图理解字符串池的工作原理以及字符串与另一个字符串相等的规则。
例如这个片段:
public static void main(String[] hi){ String s1 = "lol"; String s2 = "lol"; String s3 = new String("lol"); System.out.println( s1 == s2 );// true System.out.println( s2 == s3); // false s3.intern(); //line 1 System.out.println( s1 == s3); // false testString(s1); } private static void testString(String s1){ String s4 = "lol"; System.out.println( s1 == s4); // true }
-
在第1行:字符串被添加到字符串池中。 由于它不等于s1,我假设字符串池中有重复。 对吗?
-
在池中复制有什么规则? 换句话说,即使两个字符串具有相同的char序列,
someString == someString
何时返回false?
PS:无论如何,我在任何地方都使用string1.equals(string2)。 我只是想深入了解潜在的机制。
- 在第1行:字符串被添加到字符串池中。 由于它不等于s1,我假设字符串池中有重复。 对吗?
不,不正确。 字符串池中已经有一个字符串“lol”,因此它不会创建重复项。 但是,您没有对intern()
调用的返回值执行任何操作,因此s3
仍然引用不在池中的String
对象。
尝试s3 = s3.intern();
而不只是s3.intern();
- 在池中复制有什么规则? 换句话说,即使两个字符串具有相同的char序列,someString == someString何时返回false?
String池的重点是避免内存中重复的字符串,因此String池中不会有任何重复。
你的s3.intern();
应该是s3 = s3.intern();
获得正确的行为。
基本上我们可以通过两种方式创建Sting
String str="some data" (not bound to any object like primitive data type) String strTwo=new String("some String"); (here strTwo object contains value)
顾名思义,String Pool是存储在Java Heap
内存中的字符串池。 我们知道String是java中的特殊类,我们可以使用new运算符创建String对象,也可以用双引号提供值。
String Pool是可能的,因为String在Java中是不可变的,它是String interning概念的实现。 字符串池也是Flyweight设计模式的示例。
字符串池有助于为Java Runtime节省大量空间,尽管创建String需要更多时间。
当我们使用双引号创建一个String时,它首先在String池中查找具有相同值的String,如果发现它只返回引用,否则它在池中创建一个新String,然后返回引用。
但是,使用new运算符,我们强制String类创建一个新的String对象,然后我们可以使用intern()方法将它放入池中或从具有相同值的池中引用其他String对象。
如
public void method(){ String s1 = "Cat"; String s2 = "Cat"; String s3 = new String("Cat"); System.out.println("s1 == s2 :"+(s1==s2)); System.out.println("s1 == s3 :"+(s1==s3)); }
和输出
[![s1 == s2 :true s1 == s3 :false
将来自池(案例s1和s2)的字符串文字与将运行时创建的字符串文字或字符串与使用new创建的另一个字符串进行比较时,存在差异。
当完全相同的文字已存在时,保证字符串文字取自字符串池。 字符串对象仍在内部使用池中的字符串,但作为对象具有不同的引用。
String#intern();
返回对池中字符串的引用,这是内部使用的。
代码段显示此行为:
String literalOne = "abc"; String literalTwo = "abc"; String stringOne = new String("abc"); String stringTwo = new String("abc"); System.out.println("literalOne == literalTwo ? " + (literalOne == literalTwo)); System.out.println("stringOne == stringTwo ? " + (stringOne == stringTwo)); System.out.println("Internally stringOne == stringTwo ? " + (stringOne.intern() == stringTwo.intern())); System.out.println("Internally stringOne == literalOne ? " + (stringOne.intern() == literalOne));
并输出:
literalOne == literalTwo ? true stringOne == stringTwo ? false Internally stringOne == stringTwo ? true Internally stringOne == literalOne ? true
==比较引用,所以当你尝试s1 == s3时,你正在检查这两个引用是否指向同一个对象,因为你已经创建了s3作为一个新对象(new String(“lol”))。所以现在字符串池有两个不同的对象恰好具有相同的字符串值(“lol”),在你的代码中你有s1,s2,s4指向一个,s3指向另一个。
为了比较已引用的每个对象的值,必须使用equals()方法。