【问题标题】:Difference in the following declarations [duplicate]以下声明的差异[重复]
【发布时间】:2015-05-25 18:00:29
【问题描述】:

我无法识别以下 Java 中字符串声明的区别。

假设我有两个字符串

String str1="one";
String str2="two";

有什么区别

String str3=new String(str1+str2);

String str3=str1+str2;

在上述两个声明中,str3 的内容都是onetwo

假设我创建一个新字符串

String str4="onetwo";

那么在上述任何声明中,

if(str4==str3) {
    System.out.println("This is not executed");
}

为什么str3str4 不是指同一个对象?

【问题讨论】:

  • 不要使用==比较字符串
  • @Apurva :我想比较对象,而不是字符串的内容。我想知道str4str3 指的是哪里
  • 这实际上是在比较引用,如果 str4 和 str3 将指向相同的位置,那么它将等于这里在不同的位置......而不是使用字符串的相等方法
  • Why and where str3 and str4 are referring to different location 为什么你认为他们应该有相同的参考?
  • @kevingomes "因为 String str3=str1+str2 应该是实习生" 不,编译器无法确定非最终变量的值,因此无法连接它们在编译时,就像在"foo"+"bar" 的情况下可以做的那样并实习。它将编译成new StringBuilder(str1).append(str2).toString(),这个结果不会被实习。

标签: java string declaration string-concatenation


【解决方案1】:

str1 + str2 用于非编译常量字符串将被编译成
new StringBuilder(str1).append(str2).toString()。这个结果不会被放入,也不会从字符串池(实习字符串所在的地方)中取出。

"foo"+"bar" 的情况下是不同的故事,编译器知道他使用哪些值,所以他可以连接这个字符串一次以避免在运行时它。这样的字符串文字也将被实习。

所以String str3 = str1+str2;

String str3 = new StringBuilder(str1).append(str2).toString();

String str3 = new String(str1+str2);

一样
String str3 = new String(new StringBuilder(str1).append(str2).toString());

同样,作为方法结果生成的字符串(如substringreplacetoString)不会被保留。
这意味着您正在比较两个不同的实例(它们存储相同的字符),这就是== 返回false 的原因。

【讨论】:

    【解决方案2】:

    因为 Java 中的 Strings 是不可变的,所以编译器将优化和重用 String 字面量。因此

    String s1 = "one";
    String s2 = "one";
    s1 == s2; //true because the compiler will reuse the same String (with the same memory address) for the same string literal
    s1 == "o" + "ne"; //true because "Strings computed by constant expressions are computed at compile time and then treated as if they were literals"
    s3 = "o";
    s1 == s3 + "ne"; //false because the second string is created a run time and is therefore newly created
    

    参考http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5

    【讨论】:

    • 你使用了immutable这个词
    • may be true as the compiler may ...?这将始终为真。
    • 我相信任何编译器都会做到这一点,所以在实践中很可能是真的。但是我不认为这种行为实际上是在语言标准中定义的,所以我不想说它总是正确的,因为有效的编译器可能有不同的行为。
    • Interning Strings 与编译器无关。
    • 你说得对,字符串字面量将永远被拘留docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5 修复它。
    【解决方案3】:

    字符串有点棘手,因为要努力分享它们的表示。另外,它们是不可变的。 简短的回答是:除非您真的在低级别工作,否则您永远不应该使用“==”来比较字符串。 即使它对你有用,但对你的队友来说,这将是一场噩梦。

    要获得更长的答案和一点乐趣,请尝试以下操作:

    String s1= "a" + "b";
    String s2= "a" + "b";
    String s3=new String("a"+"b");
    
    System.out.println(s1==s2);
    System.out.println(s3==s2);
    

    您会注意到 s1==s2 由于编译器的共享努力。 但是 s2 != s3 因为您已明确要求提供新字符串。 你不可能用它做任何非常聪明的事情,因为它是不可变的。

    【讨论】:

      【解决方案4】:

      Java 没有“这个变量如何获得值”的记忆,因此,如果结果相同,则使用哪种方法并不重要。

      关于比较,如果你用==比较字符串,你是在比较内存中对象的地址,因为字符串不是原始数据类型,不是值。你必须使用if(str4.equals(str3))

      【讨论】:

      • 我只想比较对象的地址。而 str3 和 str4 有不同的引用
      • 我们使用哪种方法很重要
      • @kevingomes - 谷歌:Java 教程。实际上,在您的示例中,您想比较值,而不是内存中的地址。如果你的妻子给双胞胎生命,他们可能看起来一样,但他们是两个不同的例子。如果你想知道,如果他们看起来一样,你使用“等于”,如果你想知道,如果他们是同一个人,你使用“==”。
      猜你喜欢
      • 2013-05-28
      • 2017-11-26
      • 2013-05-23
      • 1970-01-01
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多