252

和有什么区别

String str = new String("abc");

String str = "abc";
4

13 回答 13

216

当您使用字符串文字时,字符串可以被interned,但是当您使用时,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

通常,您应该尽可能使用字符串文字表示法。它更容易阅读,它让编译器有机会优化你的代码。

于 2010-07-21T09:30:38.923 回答
87

A String literal is a Java language concept. This is a String literal:

"a String literal"

A String object is an individual instance of the java.lang.String class.

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

All are valid, but have a slight difference. s1 will refer to an interned String object. This means, that the character sequence "abcde" will be stored at a central place, and whenever the same literal "abcde" is used again, the JVM will not create a new String object but use the reference of the cached String.

s2 is guranteed to be a new String object, so in this case we have:

s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true
于 2010-07-21T09:42:10.727 回答
42

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

当你这样做时:

String str = "abc";

您正在调用Stringintern()上的方法。此方法引用内部对象池。如果您调用的 String已经存在于池中,那么对它的引用将分配给. 如果不是,则将 new放入池中,然后将对其的引用分配给.Stringintern()StringstrStringstr

给定以下代码:

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;

在这种情况下,strandstr2是对不同的引用Objects,它们都没有被interned,因此当您使用 测试Object身份时==,您将得到false.

就良好的编码实践而言:不要用于检查==字符串是否相等,.equals()而是使用。

于 2010-07-21T11:08:16.473 回答
40

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

String a = "xyz"

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

但如果你说:

String a = new String("xyz")

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

欲了解更多信息,请阅读

于 2010-07-21T12:33:44.980 回答
17

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

在 Java 中,这些文字字符串在内部进行池化,并且"abc"在您的代码中声明了该字符串文字的任何地方都使用相同的 String 实例。所以"abc" == "abc"总是如此,因为它们都是同一个 String 实例。

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

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

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

于 2010-07-21T09:33:50.447 回答
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

因为st1, st2,st3引用了 3 个不同的对象,并==检查内存位置的相等性,因此结果。

但:

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

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

在 String 声明的情况下

String st = "hello";

这里调用class的intern()方法String,检查是否"hello"在intern pool中,如果不在则加入intern pool中,如果intern pool中有hello,则st指向已有的内存"hello"

所以在以下情况下:

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

这里:

st3 == st4 // true

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

还:

st3.equals(st4);  // true as usual
于 2013-09-05T11:39:37.140 回答
6

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

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

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

于 2010-07-21T09:30:47.817 回答
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
}
于 2010-07-21T10:00:34.477 回答
5

除了已经发布的答案之外,还可以查看有关 javaranch 的这篇优秀文章。

于 2010-07-21T12:55:22.980 回答
3

根据String 类文档,它们是等价的。

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

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

于 2010-07-21T09:32:59.580 回答
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()被调用时,引用被改变。

于 2013-08-28T12:11:02.343 回答
1

字符串对象和字符串字面量之间存在细微差别。

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 ”将被放入池中。

于 2010-07-22T05:32:08.033 回答
0

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

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

于 2010-07-21T10:51:46.857 回答