Java字符串池相关疑问

3

我想了解字符串池的工作原理,浏览了许多网站,但现在更加困惑了。请允许我在这里列出我的疑问,希望有人能帮助我理解。

1)字符串池存在于哪里?是在堆中还是在方法区中?

2)String s = "Hello world"; - 这就足以创建一个字符串。由于字符串是不可变的,一旦创建了字符串,就不能改变它们,那么使用String s = new String(“Hello World”)创建字符串的必要性是什么呢?虽然它会强制JVM在堆中创建一个新的String对象,而不是在字符串池中创建。但是为什么需要强制JVM创建新的String对象呢?

3)字符串何时以及如何被垃圾回收?

提前感谢您的帮助。

3个回答

4
Java中如何处理字符串的实现方式并不重要,但有以下保证:
  1. String x = "hi"; String y = "hi"; // 确保 x == y
  2. String x = "hi"; String y = new String("hi"); // 不保证 == 但很可能 !=
  3. String x = new String("hi"); String y = new String("hi"); // 确保 != 但 x.equals(y)
  4. String x = "hi"; String y = new String("hi").intern(); // 确保 x == y
在Java8之前,String.intern()String x = "hi"会被分配到内存模型的PermGen空间中,因此它们有不同的垃圾收集机制。如果你使用String.intern(),即使有很多可用的堆空间(PermGen通常小于128MB),仍然可能会导致内存耗尽。使用new String(....)创建的字符串则位于常规堆上,具有标准的垃圾收集机制。
为什么要使用new String ("...")创建新的字符串实例?我只能想到一个场景可以这样做,那就是将生成的对象作为同步锁。这在调试时可能有意义......但并没有太多意义。必须使用“new”以防止无意中将同一字符串对象用作其他代码的同步锁。在通常的Java编码实践中,我通常不见人们使用new String ("....")。实际上,大多数情况下,人们只是使用字符串连接运算符等。但是,这并不意味着使用new String(...)是错误的。
当我查看String的源代码时,我发现代码严重依赖于String是不可变的事实。例如,new String(new String("hi"));只创建一个字符数组,并在两个String实例之间共享它(内部实例将被垃圾回收)。

0

1. 字符串池不在栈中,也不在堆中!它在方法区中! 字符串池属于常量池。因为我们都知道,常量是一个不能被改变的值,给定常量池的目的是加速程序的运行速度。在您的类文件中,例如int a = 10, String b = "123450"被视为字符串(您可以在方法中更改它们)。当类被加载时,JVM会将它们放入一个数组进行维护,并将此数组放入名为字符串池的方法区。

2. 当你创建一个字符串对象时,你可以这样做:String str1 = new String("abc")String str2 = "abc";。它们看起来一样,但 JVM 处理它们的方式不同。对于第一个,JVM 会在堆中创建一个字符串对象,并将其返回给用户。但是对于第二个,JVM 将使用字符串的equals()方法检查字符串池是否存在该字符串对象。如果是,则将该字符串对象返回给用户,并且不会重新创建一个新的字符串对象。如果字符串池中没有该字符串对象,则 JVM 将在堆中创建一个新的对象并将其返回给用户,同时将其放入字符串池中。

String str1 = new String("abc"); //jvm creates a String object in Heap.

 //jvm can not find "abc" in String pool  
 //Create a String object in heap,and put it in strings pool   
 //Now heap has two string object.
Stirng str2 = "abc";   

 if(str1 == str2){   
         System.out.println("str1 == str2");   
 }else{   
         System.out.println("str1 != str2");   
 }   
  //Print result is  str1 != str2, because they are different objects in heap

  String str3 = "abc";   

 //Now,jvm realizes String Pool already had “abc” object,because “abc”equals “abc”

  if(str2 == str3){   
         System.out.println("str2 == str3");   
  }else{   
         System.out.println("str2 != str3");   
  }   
 //Print result is str2 == str3  



String str1 = new String("abc"); 

str1 = str1.intern();   


Stirng str2 = "abc";   

 if(str1 == str2){   
         System.out.println("str1 == str2");   
 }else{   
         System.out.println("str1 != str2");   
 }  //Print: str1 == str2   

0

字符串池就像一个桶,其中包含了String常量。 例如:

Object a = new Object();
Object b = new Object();

它将在堆中创建两个新对象。

但是,

String s1 = "abc";
String s2 = "abc";

由于它们是常量,它将仅在 字符串池 中创建一个对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接