字符串对象和字符串文字的区别

两者有什么区别

String str = new String("abc");

而且

String str = "abc";
301809 次浏览

当你使用字符串字面值时,字符串可以是< / em > < em >拘留,但当你使用new String("...")时,你会得到一个新的字符串对象。

在这个例子中,两个字符串字面值引用同一个对象:

String a = "abc";
String b = "abc";
System.out.println(a == b);  // true

这里创建了2个不同的对象,它们有不同的引用:

String c = new String("abc");
String d = new String("abc");
System.out.println(c == d);  // false

一般来说,应该尽可能使用字符串文字表示法。它更容易阅读,并给编译器优化你的代码的机会。

在第一种情况下,创建了两个对象。

在第二种情况下,它只是一个。

尽管这两种方式str都指向"abc"

根据字符串类文档,它们是等价的。

String(String original)的文档也说:除非需要original的显式副本,否则使用此构造函数是不必要的,因为string是不可变的。

寻找其他的回答,因为Java文档似乎是误导性的:(

"abc"是一个字符串字面值。

在Java中,这些字面值字符串是内部池,并且在代码中声明该字符串字面值时使用"abc"的相同String实例。因此"abc" == "abc"将始终为真,因为它们都是相同的String实例。

使用String.intern()方法,你可以将你喜欢的任何字符串添加到内部池字符串中,这些字符串将一直保存在内存中,直到java退出。

另一方面,使用new String("abc")将在内存中创建一个新的字符串对象,这在逻辑上与"abc"字面量相同。 "abc" == new String("abc")将始终为false,因为尽管它们在逻辑上相等,但它们引用不同的实例

将String构造函数包装在字符串文字周围是没有价值的,它只是不必要地使用比它需要的更多内存。

字符串文字是一个Java语言概念。这是一个String字面值:

"a String literal"

字符串对象java.lang.String类的一个单独实例。

String s1 = "abcde";
String s2 = new String("abcde");
String s3 = "abcde";

都是有效的,但有细微的区别。s1将引用一个实习过 String对象。这意味着,字符序列"abcde"将被存储在一个中心位置,每当再次使用相同的字面"abcde"时,JVM将不会创建一个新的String对象,而是使用缓存 String的引用。

s2肯定是new String对象,所以在这种情况下,我们有:

s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true

一些拆卸总是很有趣的……

$ cat Test.java
public class Test {
public static void main(String... args) {
String abc = "abc";
String def = new String("def");
}
}


$ javap -c -v Test
Compiled from "Test.java"
public class Test extends java.lang.Object
SourceFile: "Test.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method  #7.#16;  //  java/lang/Object."<init>":()V
const #2 = String  #17;     //  abc
const #3 = class   #18;     //  java/lang/String
const #4 = String  #19;     //  def
const #5 = Method  #3.#20;  //  java/lang/String."<init>":(Ljava/lang/String;)V
const #6 = class   #21;     //  Test
const #7 = class   #22;     //  java/lang/Object
const #8 = Asciz   <init>;
...


{
public Test(); ...


public static void main(java.lang.String[]);
Code:
Stack=3, Locals=3, Args_size=1
0:    ldc #2;           // Load string constant "abc"
2:    astore_1          // Store top of stack onto local variable 1
3:    new #3;           // class java/lang/String
6:    dup               // duplicate top of stack
7:    ldc #4;           // Load string constant "def"
9:    invokespecial #5; // Invoke constructor
12:    astore_2          // Store top of stack onto local variable 2
13:    return
}

String s = new String("FFFF")创建了2个对象:"FFFF"字符串和String对象,它们指向"FFFF"字符串,所以它就像指针到指针(引用到引用,我不喜欢术语)。

据说你永远不应该使用new String("FFFF")

长答案是可用的在这里,所以我给你一个简短的。

当你这样做的时候:

String str = "abc";

你正在调用字符串上的intern()方法。String对象的引用内部池方法。如果你调用intern()的字符串已经存在于池中,那么对该String的引用将被赋值给str。如果不是,则将新的String放在池中,然后将对它的引用赋给str

给定以下代码:

String str = "abc";
String str2 = "abc";
boolean identity = str == str2;

当你通过执行==来检查对象身份时(你实际上是在问:这两个引用是否指向同一个对象?),你会得到true

但是,你不能将abc3转换为intern() Strings。你可以通过这样做强制在堆上的一个新的Object上创建:

String str = new String("abc");
String str2 = new String("abc");
boolean identity = str == str2;

在这个例子中,strstr2是对不同Objects的引用,它们都不是实习过,所以当你使用==测试Object身份时,你会得到false

在良好的编码实践方面:如果使用==来检查String是否相等,则使用.equals()来代替。

由于字符串是不可变的,当你这样做时:

String a = "xyz"

在创建字符串时,JVM在字符串池中搜索是否已经存在字符串值"xyz",如果存在,'a'将只是该字符串的引用,并且不会创建新的string对象。

但如果你说:

String a = new String("xyz")

你强迫JVM创建一个新的String引用,即使"xyz"在它的池中。

更多信息请阅读

除了已经发布的答案,还可以查看关于javaranche的优秀文章。

字符串对象和字符串文字之间有细微的区别。

String s = "abc"; // creates one String object and one reference variable

在这个简单的例子中,"美国广播公司"将进入池,年代将引用它。

String s = new String("abc"); // creates two objects,and one reference variable
在本例中,因为我们使用了new关键字,Java将创建一个新的String对象 在正常(非池)内存中,年代将引用它。此外,字面量“美国广播公司”将

以下是一些比较:

String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");


System.out.println(s1 == s2); //true
System.out.println(s1.equals(s2)); //true


System.out.println(s1 == s3);   //false
System.out.println(s1.equals(s3)); //true


s3 = s3.intern();
System.out.println(s1 == s3); //true
System.out.println(s1.equals(s3)); //true

intern()被调用时,引用被改变。

String是Java中不同于其他编程语言的一个类。因此,对于每个类,对象的声明和初始化是

String st1 = new String();

String st2 = new String("Hello");
String st3 = new String("Hello");

这里,st1st2st3是不同的对象。

那就是:

st1 == st2 // false
st1 == st3 // false
st2 == st3 // false

因为st1st2st3引用了3个不同的对象,而==检查内存位置是否相等,因此结果为。

但是:

st1.equals(st2) // false
st2.equals(st3) // true

这里.equals()方法检查内容,以及st1 = ""st2 = "hello"st3 = "hello"的内容。这就是结果。

在String声明的情况下

String st = "hello";

这里调用String类的intern()方法,并检查"hello"是否在实习生池中,如果不在,则将其添加到实习生池中,如果“hello”存在于实习生池中,则st将指向现有"hello"的内存。

所以在这种情况下:

String st3 = "hello";
String st4 = "hello";

在这里:

st3 == st4 // true

因为st3st4指向相同的内存地址。

另外:

st3.equals(st4);  // true as usual