Mar*_*ers 203

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

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

String a = "abc"; 
String b = "abc";
System.out.println(a == b);  // true
Run Code Online (Sandbox Code Playgroud)

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

String c = new String("abc");
String d = new String("abc");
System.out.println(c == d);  // false
Run Code Online (Sandbox Code Playgroud)

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

  • 在实践中,你通常会看到`new String(...)`的使用不是因为有人想要这里描述的行为,而是因为他们不知道字符串是不可变的.所以你看到像'b = new String(a); b = b.substring(2);`而不仅仅是`b = a.substring(2)`因为作者可能认为substring方法将修改调用它的实例.虽然这是真的`"abc"=="abc"`我会说_in general_代码依赖于这而不是使用equals(...)是聪明的,容易混淆的东西(静态最终"常量"是一个例外). (16认同)
  • @broofa:这在JavaScript中有什么用? (5认同)

And*_*s_D 86

一个文本字符串是Java语言的概念.这是一个字符串文字:

"a String literal"
Run Code Online (Sandbox Code Playgroud)

字符串对象是的单个实例java.lang.String的类.

String s1 = "abcde";
String s2 = new String("abcde");
String s3 = "abcde";
Run Code Online (Sandbox Code Playgroud)

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

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

s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true
Run Code Online (Sandbox Code Playgroud)

  • 许多语言都有String Literal的概念:) (16认同)
  • 那么这是否意味着文字字符串"abc"仍然是一个像`new String("abc")`这样的对象,唯一的区别是它存储在实习池而不是堆中? (3认同)

Jon*_*Jon 41

长的答案,请点击这里,让我给你的短之一.

当你这样做:

String str = "abc";
Run Code Online (Sandbox Code Playgroud)

您正在调用Stringintern()上的方法.此方法引用了一个内部池的对象.如果您调用的String 已驻留在池中,则会为其分配对该引用的引用.如果没有,则将新的放置在池中,然后为其分配对它的引用.Stringintern()StringstrStringstr

给出以下代码:

String str = "abc";
String str2 = "abc";
boolean identity = str == str2;
Run Code Online (Sandbox Code Playgroud)

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

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

String str = new String("abc");
String str2 = new String("abc");
boolean identity = str == str2;
Run Code Online (Sandbox Code Playgroud)

在这个例子中,str并且str2是对不同的引用Objects,它们都没有被实习,所以当你Object使用时测试身份==,你就会得到false.

在良好的编码实践两方面:千万不能使用==检查字符串是否相等,用.equals()代替.

  • EJB,从什么时候编译器创建对象?编译后的字节代码可能会在10年后在另一台机器上运行.JVM的工作是创建String对象.根据机器语言规范(3.10.5),`字符串文字是对类String的实例的引用.规范甚至承诺它将是不同类和包的相同实例.你可能会想到一个"不断表达".代码"Hello"+"World"将由**编译器**重写为"Hello World". (2认同)

Awi*_*win 36

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

String a = "xyz"
Run Code Online (Sandbox Code Playgroud)

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

但如果你说:

String a = new String("xyz")
Run Code Online (Sandbox Code Playgroud)

您强制JVM创建新String引用,即使"xyz"它在池中.

欲了解更多信息,请阅读.

  • 链接现在已经破了,我猜这是这篇文章:http://javatechniques.com/blog/string-equality-and-interning/ (2认同)

kro*_*ock 17

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

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

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

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

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


NCA*_*NCA 7

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

String st1 = new String();
Run Code Online (Sandbox Code Playgroud)

要么

String st2 = new String("Hello"); 
String st3 = new String("Hello");
Run Code Online (Sandbox Code Playgroud)

这里st1,st2而且st3是不同的对象.

那是:

st1 == st2 // false
st1 == st3 // false
st2 == st3 // false
Run Code Online (Sandbox Code Playgroud)

因为st1,st2,st3正在引用3个不同的对象,并且==检查在存储器位置中的平等,因此结果.

但:

st1.equals(st2) // false
st2.equals(st3) // true
Run Code Online (Sandbox Code Playgroud)

在此.equals()方法检查的内容,内容st1 = "",st2 = "hello"st3 = "hello".因此结果.

并且在String声明的情况下

String st = "hello";
Run Code Online (Sandbox Code Playgroud)

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

所以在以下情况下:

String st3 = "hello";
String st4 = "hello"; 
Run Code Online (Sandbox Code Playgroud)

这里:

st3 == st4 // true
Run Code Online (Sandbox Code Playgroud)

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

也:

st3.equals(st4);  // true as usual
Run Code Online (Sandbox Code Playgroud)


sus*_*ani 6

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

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

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


aio*_*obe 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
}
Run Code Online (Sandbox Code Playgroud)


Zak*_*aki 5

除了已经发布的答案,还可以看到关于javaranch的这篇优秀文章.