请考虑以下 2 行 Java 代码:
String s = new String("Hello");
String s1 = s.toUpperCase();
在上面的代码中,当我们在 String 上调用 toUpperCase() 方法时,将创建多少个对象。一个对象是在堆中创建还是在字符串常量池中创建,还是只在堆中创建? 我知道 toUpperCase() 会在堆中创建一个新对象。但是想知道会不会也放到String常量池里
答案是......这取决于。
我们可以肯定地说的一件事是,无论是
toUpperCase()
还是subString()
都不会在字符串池1中放置一个
String
。唯一指定为(可能)将 String
添加到字符串池的 String
操作是 intern()
.
我们不能肯定地说
toUpperCase()
和subString()
会生成一个新的String
对象。例如,在 Java 11 中,str.substring(0)
返回 str
本身。这是一个实现细节,但是许多操作的 javadoc 措辞如此,如果 this
满足要求,则返回 this
是有效的。
在创建新
String
的情况下,创建对象的方式取决于实现。 Java 字符串通常表示为一个 String
对象,它引用了表示字符串字符的后备 char[]
或 byte[]
。但是在某些 Java 版本中,支持数组可以在多个 String
对象之间共享......在某些情况下。事实上,substring
是使用共享后备阵列创建 String
的方法之一。
最后,正如一位评论者所指出的,这些东西与现实世界中的 Java 编程无关……除了最极端的情况。通常,你应该让 JVM 处理这种东西。
1 - 它是字符串池而不是“常量字符串池”。 “常量池”实际上是类文件中存在的东西。但是字符串池中可能包含不对应Java常量的字符串。
看待这个问题的另一种方法是理解 Java 中的字符串是不可变的。此外,它们是在堆内存中创建的。
String Literals 在堆内存中创建,但也放入字符串池中。
在您的代码中,以下行创建了一个 String 对象(不是文字)
String s = new String("Hello");
所以它在堆中创建了一个对象。它不会向字符串池添加任何内容。
以下行在堆中创建另一个对象。即使它不会向字符串池添加任何内容。
String s1 = s.toUpperCase();
所以,在你的例子中。将在堆中创建 2 个对象。字符串池中不会创建新对象。
看看这个答案