这两个陈述之间有什么区别?
String s = "text";
String s = new String("text");
Run Code Online (Sandbox Code Playgroud)
pol*_*nts 180
new String("text");
显式创建一个新的和引用不同的String
对象实例; String s = "text";
可以重用字符串常量池中的实例(如果有).
你很少想要使用new String(anotherString)
构造函数.来自API:
String(String original)
:初始化新创建的String
对象,使其表示与参数相同的字符序列; 换句话说,新创建的字符串是参数字符串的副本.除非需要显式的原始副本,否则不需要使用此构造函数,因为字符串是不可变的.
检查以下代码段:
String s1 = "foobar";
String s2 = "foobar";
System.out.println(s1 == s2); // true
s2 = new String("foobar");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
Run Code Online (Sandbox Code Playgroud)
==
两种引用类型是引用标识比较.两个equals
不一定的对象==
.==
在引用类型上使用通常是错误的; 大部分时间都equals
需要使用.
尽管如此,如果出于某种原因需要创建两个equals
但不是==
字符串,则可以使用new String(anotherString)
构造函数.然而,需要再说一遍,这是非常奇特的,很少是意图.
Bra*_*raj 112
字符串文字将进入字符串常量池.
下面的快照可能会帮助您直观地理解它以便记住它更长的时间.
逐行创建对象:
String str1 = new String("java5");
Run Code Online (Sandbox Code Playgroud)
在构造函数中使用字符串文字"java5",新的字符串值存储在字符串常量池中.使用new运算符,在堆中创建一个新的字符串对象,并将"java5"作为值.
String str2 = "java5"
Run Code Online (Sandbox Code Playgroud)
引用"str2"指向字符串常量池中已存储的值
String str3 = new String(str2);
Run Code Online (Sandbox Code Playgroud)
在堆中创建一个新的字符串对象,其值与"str2"引用的值相同
String str4 = "java5";
Run Code Online (Sandbox Code Playgroud)
引用"str4"指向字符串常量池中已存储的值
总对象:堆 - 2,池 - 1
小智 15
一个在字符串常量池中创建一个String
String s = "text";
Run Code Online (Sandbox Code Playgroud)
另一个在常量池("text"
)中创建一个字符串,在普通堆空间(s
)中创建另一个字符串.两个字符串都具有相同的值,即"text".
String s = new String("text");
Run Code Online (Sandbox Code Playgroud)
s
如果以后未使用,则会丢失(符合GC条件).
另一方面,字符串文字被重用.如果您"text"
在类的多个位置使用它实际上将是一个且只有一个String(即对池中相同字符串的多个引用).
这个概念被JLS称为"实习".
此外,字符串文字始终引用类String的相同实例.这是因为字符串文字 - 或者更常见的是作为常量表达式(第15.28节)的值的字符串 - 被"实例化"以便使用String.intern方法共享唯一实例.
例3.10.5-1.字符串文字
该程序由编译单元组成(第7.3节):
Run Code Online (Sandbox Code Playgroud)package testPackage; class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); System.out.print((Other.hello == hello) + " "); System.out.print((other.Other.hello == hello) + " "); System.out.print((hello == ("Hel"+"lo")) + " "); System.out.print((hello == ("Hel"+lo)) + " "); System.out.println(hello == ("Hel"+lo).intern()); } } class Other { static String hello = "Hello"; }
和编译单位:
Run Code Online (Sandbox Code Playgroud)package other; public class Other { public static String hello = "Hello"; }
产生输出:
Run Code Online (Sandbox Code Playgroud)true true true true false true
字符串文字是对类String实例的引用,它是从类或接口的二进制表示形式的CONSTANT_String_info结构(第4.4.3节)派生而来的.CONSTANT_String_info结构给出了构成字符串文字的Unicode代码点序列.
Java编程语言要求相同的字符串文字(即包含相同代码点序列的文字)必须引用类String的相同实例(JLS§3.10.5).此外,如果在任何字符串上调用String.intern方法,则结果是对该字符串显示为文字时将返回的同一类实例的引用.因此,以下表达式的值必须为true:
Run Code Online (Sandbox Code Playgroud)("a" + "b" + "c").intern() == "abc"
为了派生字符串文字,Java虚拟机检查CONSTANT_String_info结构给出的代码点序列.
如果先前在类String的实例上调用了String.intern方法,该类包含与CONSTANT_String_info结构给出的Unicode代码点序列相同的Unicode代码点序列,则字符串文字派生的结果是对类String的同一实例的引用.
否则,将创建一个类String的新实例,其中包含CONSTANT_String_info结构给出的Unicode代码点序列; 对该类实例的引用是字符串文字派生的结果.最后,调用新String实例的intern方法.
查看OpenJDK 7上的字节码实现也很有启发性.
如果我们反编译:
public class StringPool {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
String c = new String("abc");
System.out.println(a);
System.out.println(b);
System.out.println(a == c);
}
}
Run Code Online (Sandbox Code Playgroud)
我们有恒定的池:
#2 = String #32 // abc
[...]
#32 = Utf8 abc
Run Code Online (Sandbox Code Playgroud)
并且main
:
0: ldc #2 // String abc
2: astore_1
3: ldc #2 // String abc
5: astore_2
6: new #3 // class java/lang/String
9: dup
10: ldc #2 // String abc
12: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne 42
38: iconst_1
39: goto 43
42: iconst_0
43: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
Run Code Online (Sandbox Code Playgroud)
请注意:
0
和3
:ldc #2
加载相同的常量(文字)12
:创建一个新的字符串实例(使用#2
as参数)35
:a
和c
作为常规对象进行比较if_acmpne
常量字符串的表示在字节码上非常神奇:
new String
并且上面的JVMS引用似乎表明只要Utf8指向的是相同的,就会加载相同的实例ldc
.
我已经对字段进行了类似的测试,并且:
static final String s = "abc"
通过ConstantValue属性指向常量表ldc
结论:对字符串池有直接的字节码支持,并且内存表示是有效的.
额外:将其与整数池进行比较,整数池没有直接的字节码支持(即没有CONSTANT_String_info
模拟).
归档时间: |
|
查看次数: |
73788 次 |
最近记录: |