我有下面的字符串
String str1 = "Abc";//created in constant pool
String str2 = "XYZ";//created in constant pool
String str3 = str1 + str2;//created in constant pool
String str4 = new String("PQR");//created in heap
String str5 = str1.concat(str4);//created in heap
String str6 = str1 + str4;//created in heap
Run Code Online (Sandbox Code Playgroud)
在这里,我不知道为什么将字符串(在常量池中创建,而另一个在堆中创建)的串联导致在堆中创建新字符串String。我不知道原因,为什么会发生?
Ste*_*n C 13
评论中有很多可疑的信息,因此我将给出一个正确的答案。
实际上,没有 “恒定池”之类的东西。您不会在Java语言规范中找到该术语。
(也许您将术语与作为.class文件一部分的常量池和相应的每类运行时常量池相混淆,后者对应用程序不可见。这些是JVM定义的“规范工件”规范,用于定义字节码的执行模型。该规范并不需要物理存在,尽管它们通常存在;例如,在Oracle或OpenJDK实现中。
正在运行的JVM中有一个数据结构,称为字符串池。在JLS中未按名称提及字符串池,但是JLS指定的字符串文字属性暗含了它的存在。字符串池在javadocs和JVM规范中都有提及。
字符串池将包含String表示应用程序中使用的任何字符串值常量表达式的值的对象。这包括字符串文字。
字符串池一直以来一直是字符串的重复数据删除机制。应用程序可以通过调用String.intern方法来使用此方法。
常量池中的字符串值(请参见上文)用于创建String应用程序看到的对象:
String表示创建对象。String.intern会被调用,并String从字符串池中返回相应的重复数据删除对象。字符串池是并且一直存储在(或)堆中。
在Java 7之前,字符串池中的字符串对象是在称为PermGen堆的特殊堆中分配的。在Java的最早版本中,它不是通过GC进行的。然后只是偶尔进行了GC处理。
在Java 7中(不是8!),字符串池使用PermGen堆停止,而使用常规堆。
在Java 8中,PermGen堆(出于某些目的!)被称为Metaspace的另一种存储管理机制所替代。显然,Metaspace不包含Java对象。相反,它包含代码段,类描述符和其他JVM内部数据结构。
在Java的最新版本(即Java 8 u20和更高版本)中,GC具有另一种机制,可对在给定数量的GC周期后仍可幸存的字符串进行重复数据删除。
字符串的行为(即哪些是被插入的,哪些不是)由JLS和String类的javadocs的相关部分确定。
如果遵循一个简单的规则,那么所有的复杂性都不相关:
切勿用于
==比较字符串。始终使用equals。
现在来处理您的示例代码:
String str1 = "Abc"; // string pool
String str2 = "XYZ"; // string pool
String str3 = str1 + str2; // not string pool (!!)
String str3a = "Abc" + "XYZ"; // string pool
String str4 = new String("PQR"); // not string pool (but the "PQR" literal is)
String str5 = str1.concat(str4); // not string pool
String str6 = str1 + str4; // not string pool
String str7 = str6.intern(); // string pool
Run Code Online (Sandbox Code Playgroud)
为什么?
str1,str2并且str3a是常量表达式的所有值; 见下文。str3根据JLS,分配给它的值不是常量表达式的值。str4-JLS表示new操作员始终创建一个新对象,并且不会自动插入新字符串str5-字符串操作除了intern不在字符串池中创建对象外str6-同上-等同于concat通话。JLS还说+产生一个新的字符串(在常量表达式的情况下除外)。str7-例外:见上文。该intern调用将在字符串池中返回一个对象。常量表达式包括文字,包含文字的串联,常量的值static final String以及其他一些东西。有关完整列表,请参见JLS 15.28。但请记住,字符串池仅保存字符串值。
的确切行为intern取决于Java版本。考虑以下示例:
char[] chars = // create an array of random characters
String s1 = new String(chars);
String s2 = s1.intern();
Run Code Online (Sandbox Code Playgroud)
让我们假设随机字符不对应于任何以前的中断字符串。
对于在PermGen中分配了内部字符串的较早JVM,intern示例中的调用将(必须)产生一个新String对象。
对于较新的JVM,intern可以将现有的String对象添加到字符串池数据结构中,而无需创建新String对象。
换句话说,真相s1 == s2取决于Java版本。
| 归档时间: |
|
| 查看次数: |
105 次 |
| 最近记录: |