Java中的String类内部是如何工作的?

3
String类是如何工作的?我看了很多帖子,但没有找到答案。
String str="ABC";

上述语句是否调用构造函数?
public String(char[] paramArrayOfChar)

如果是的话,它该如何称呼?我们使用赋值运算符。它如何调用String类的构造函数。


1
你要寻找的答案可以在这里找到:http://stackoverflow.com/questions/7088928/java-strings-how-do-they-work - Twahanz
一个可能会让那些之前学过 C 和/或 C++ 的人感到困惑的原因是,字面值 "ABC" 不是 char 数组。它已经是一个 String,并且在它所出现的方法被调用之前就已经作为一个 String 对象存在了。因此,没有必要调用任何构造函数。语句 String str = "ABC" 只是分配了一个 引用 - Klitos Kyriacou
@KlitosKyriacou,我认为,在C语言中,字符串字面量一个const char[]数组。 - Andrew Tobilko
@AndrewTobilko,你是对的,我表述有误:我的意思是那些学过C和/或C++的人知道"ABC"是一个const char[]字面量,但在Java中不是这样。在Java中,这个字面量从一开始就是一个String对象。 - Klitos Kyriacou
“字符串字面量是对 String 类实例的引用”(Java 语言规范第 8 版)。JLS 没有指定 String 包含 char 数组作为基础(API 文档也没有),因为这是一个实现细节。 - Klitos Kyriacou
显示剩余2条评论
5个回答

1
这比较复杂。在Java中,字符串存储在全局存储区中,因此构造函数可能只调用一次,JVM决定将哪些字符串“intern”(放入全局存储区),如果再次声明“ABC”,它可能是相同的实例。

1
上述语句是否调用构造函数?
不,它没有。如果字符串池中不包含“ABC”,它看起来像String str = new String("ABC")。当您再次写入"ABC"时,它将使用内部存储中的旧版本。如果池已经包含此值-没有创建对象,只是从存储中提取此值(当我们谈论使用String字面量如"ABC"时,这是正确的,但当我们使用new关键字时,行为略有different)。 "ABC"是已定义的对象,其中内部包含value作为char[] {'A','B','C'}。我可以假设某个地方创建了"ABC"实例作为new String(new char[]{'A','B','C'})(规范对此没有任何说明)。

如果字符串池中不包含“ABC”,它会调用String构造函数吗?如果是,我想了解它是如何调用构造函数的。 - alakhya
@alakhya,构造函数没有被调用,"ABC"的值从字符串池中返回。 - Andrew Tobilko

1
因为字符串是编程中常见且重要的部分,Java 在语言的语法中添加了对几种字符串操作的特殊支持。这些操作包括从字符串字面值自动创建新的 String 实例、通过使用 + 运算符连接多个 String 对象以及将其他数据类型转换为字符串表示形式。虽然有可用于执行所有这些功能的显式方法,但 Java 会自动执行它们作为程序员的方便和增加清晰度。
字符串字面值
之前的示例展示了如何使用 new 运算符从字符数组中显式创建一个 String 实例。然而,有一种更简单的方法可以使用字符串字面值来完成。对于程序中的每个字符串字面值,Java 自动构造一个 String 对象。因此,您可以使用字符串字面值来初始化 String 对象。例如,下面的代码片段创建了两个等价的字符串:
char chars[] = { 'a', 'b', 'c' };
String s1 = new String(chars);
String s2 = "abc"; // use string literal

由于每个字符串字面量都会创建一个String对象,因此您可以在任何可以使用String对象的地方使用字符串字面量。例如,您可以直接在引号字符串上调用方法,就像它是一个对象引用一样,如下语句所示。它在字符串“abc”上调用length()方法。正如预期的那样,它打印出“3”。 System.out.println("abc".length());

1

编辑 当我们想像这样使用它 String str1 = "Hello World"; 时,我们正在使用String Interning(顺便说一下,它被许多编程语言使用):

在计算机科学中,字符串驻留是一种方法,只存储每个不同字符串值的一个副本,该值必须是不可变的。将字符串驻留使得某些字符串处理任务更加时间或空间有效,但代价是创建或驻留字符串时需要更多时间。不同的值存储在字符串内部池中。

JVM 首先检查 String constant pool,如果字符串不存在,则会创建一个新的 String 对象,如何呢?当在 String 对象上调用 intern() 方法时,它查找此 String 对象中包含的字符串,在 中找到该字符串,则返回池中的字符串。否则,将该 String 对象添加到池中,并返回对该 String 对象的引用。

例子:
// s1 == s2 is false
String s1 = new String("sometext");
// s1 == s2 is true
//String s1 = new String("sometext").intern();
String s2 = s1.intern();
String s3 = "sometext";
System.out.println(s2 == s3);

另一个例子(读取 abbas 的值并更改它)
        String str = "abbas";
        Field value = str.getClass().getDeclaredField("value");
        value.setAccessible(true);
        char[] Value = (char[]) value.get(str);
        System.out.println("Value = " + Arrays.toString(Value));

        char[] newVal = new char[]{'f','t','b','h','p'};
        value.set(str,newVal);
        Value = (char[]) value.get(str);
        System.out.println("Value = " + Arrays.toString(Value));
        //Value = [a, b, b, a, s]
        //Value = [f, t, b, h, p]

-1
在字符串字面量的部分,Java语言规范没有指定字符串是如何创建的。它只指定了使用String.intern()进行内部化。
因此,不能保证实现会如何创建字符串。

String.intern() 不会创建一个新的字符串。 - JB Nizet

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