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

时间:2010-07-21 09:29:12

标签: java string string-literals

之间有什么区别
String str = new String("abc");

String str = "abc";

13 个答案:

答案 0 :(得分:202)

当您使用字符串文字时,字符串可以是interned,但是当您使用new String("...")时,您将获得一个新的字符串对象。

在此示例中,两个字符串文字都引用相同的对象:

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

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

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

通常,应尽可能使用字符串文字表示法。它更容易阅读,它为编译器提供了优化代码的机会。

答案 1 :(得分:85)

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

"a String literal"

String对象java.lang.String类的单个实例。

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

一切都有效,但略有不同。 s1将引用 interned String对象。这意味着,字符序列"abcde"将存储在中心位置,并且每当再次使用相同的文字"abcde"时,JVM将不会创建新的String对象,而是使用< em> cached String。

s2保证是新的String对象,所以在这种情况下我们有:

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

答案 2 :(得分:40)

答案很长here,所以我会给你一个简短的答案。

执行此操作时:

String str = "abc";

您正在String上调用intern()方法。此方法引用String个对象的内部池。如果您调用的intern()上的字符串已驻留在池中,则会将String的引用分配给str。如果没有,则新的String将被放置在池中,然后将对它的引用分配给str

给出以下代码:

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

当您通过==检查对象标识时(您实际上是在询问:这两个引用是否指向同一个对象?),您得到true

但是,您需要intern() Strings。您可以通过执行以下操作强制在堆上的新Object上创建:

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

在这种情况下,strstr2是对不同Objects的引用,其中没有 interned ,因此当您测试{{ 1}}使用Object进行身份识别,您将获得==

在良好的编码实践方面:使用false来检查字符串是否相等,而是使用==

答案 3 :(得分:35)

由于字符串是不可变的,所以:

String a = "xyz"

在创建字符串时,如果已存在字符串值"xyz",则JVM在字符串池中搜索,如果是,'a'将只是该字符串的引用,并且没有新的String对象是创建

但如果你说:

String a = new String("xyz")

即使String位于其池中,您也会强制JVM创建新的"xyz"引用。

有关详细信息,请参阅this

答案 4 :(得分:17)

"abc"是一个文字字符串。

在Java中,这些文字字符串在内部汇集,并且在代码中声明了字符串文字的地方使用"abc"的相同String实例。所以"abc" == "abc"将永远为真,因为它们都是相同的String实例。

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

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

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

答案 5 :(得分:7)

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";

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

以下是:

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

下面:

st3 == st4 // true

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

此外:

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

答案 6 :(得分:6)

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

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

虽然str两种方式都指的是"abc"

答案 7 :(得分:5)

有些反汇编总是很有意思......

$ 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
}

答案 8 :(得分:5)

除了已发布的答案外,另请参阅this关于javaranch的优秀文章。

答案 9 :(得分:3)

根据String class documentation,它们是等效的。

String(String original)的文档也说:除非需要明确的原始副本,否则不必使用此构造函数,因为字符串是不可变的。

寻找其他响应,因为Java文档似乎具有误导性:(

答案 10 :(得分:2)

以下是一些比较:

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()时,引用会更改。

答案 11 :(得分:1)

String对象和字符串文字之间存在细微差别。

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

在这个简单的情况下,“ abc ”将进入池中, s 将引用它。

String s = new String("abc"); // creates two objects,and one reference variable

在这种情况下,因为我们使用了new关键字,Java将创建一个新的String对象 在普通(非池)内存中, s 将引用它。另外,文字“ abc ”会 放在游泳池里。

答案 12 :(得分:0)

String s = new String("FFFF")创建了2个对象:"FFFF"字符串和String对象,它指向"FFFF"字符串,所以它就像指向指针(引用参考,我是不热衷于术语。)

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