【问题标题】:string.concat(string) function, why my code is giving false in the outputstring.concat(string) 函数,为什么我的代码在输出中给出 false
【发布时间】:2021-03-31 09:57:20
【问题描述】:
String s1="Hello";
s1=s1.concat("World");
String s2="HelloWorld";
    
System.out.println(s1);
System.out.println(s2);
System.out.println(s2==s1); //false

在连接之后,“HelloWorld”字符串在字符串常量池中创建,我们正在创建另一个具有相同单词“HelloWorld”的字符串,然后它已经存在于字符串常量池中,因此它返回现有的引用。 那么,为什么我的代码在输出中给出了 false 呢?

String s1="Hello";
    String s2="HelloWorld";
    
    s1=s1.concat("World");

    System.out.println(s1);
    System.out.println(s2);
    System.out.println(s2==s1);//false
String s1="Hello";
    s1=s1+"World";

    String s2="HelloWorld";

    
    System.out.println(s1);
    System.out.println(s2);
    System.out.println(s2==s1);//false

为什么是假的?? 为什么他们指向不同的参考。 因为这个词已经存在于字符串常量池中。那么如果我们形成一个具有相同值的新字符串对象,那么它应该指向已经存在的对象。

【问题讨论】:

  • 这是什么语言?
  • 语言 - Java
  • "由于连接后,"HelloWorld" 字符串会在字符串常量池中创建" 不,只有在 (a)您使用+ 作为连接运算符,而不是concatenate 方法和(b) 如果您连接编译时间常数。这些条件都不满足。
  • s1+"World" s1 不是编译时间常数,因为编译器不能确定s1 的值,因为它不是final。试试final String s1="Hello"; 看看有什么不同。您还需要为连接结果声明新变量,因为您无法将该结果重新分配回已经初始化的 s1。所以你需要像String s3 = s1 + "World"; 这样的东西,然后比较s2 and s3 而不是s2 and s1
  • @ArvindKumarAvinash 我确信 Jon Skeet 的某个答案可以更好地解释它。现在的主要目标是找到答案并将这个问题链接到它:)

标签: java string stringbuilder stringbuffer string-constant


【解决方案1】:

默认情况下,字符串不具有相同的标识。仅当字符串被interned 时,才返回字符串池中的字符串。

结果完全来自常量表达式的所有字符串值或字符串连接都将自动实习。常量表达式是其值在编译时已知的表达式。其中包括:

  • 文字;和
  • final 原始类型变量或String 类。

例子:

String a = "Hello" + "World";   // 'HelloWorld'
String b = "Hi" + 23 + "There"; // 'Hi23There'
final int i = 47 + 100;
String c = "Number" + i + '!';  // 'Number147!'

这是在Java Language Specification, § 15.28 中定义的。

您的用例不满足这些要求,因此您的结果是false。您可以通过调用Strings intern() 方法触发字符串实习。如果您改为写s1 = s1.concat("World").intern();,那么结果将是true

【讨论】:

    【解决方案2】:

    您需要使用 equals 而不是 == ,因此您的代码必须类似于 System.out.println(s2.equals(s1))

    我们可以使用 == 操作符进行引用比较(地址比较)和 .equals() 方法进行内容比较。简单来说, == 检查两个对象是否指向相同的内存位置,而 .equals() 计算对象中值的比较。

    【讨论】:

    • 不,我在比较参考。所以这就是为什么使用 ==。
    • String s1="Hello"; s1=s1.concat("世界"); JVM 获取字符串 s1("Hello") 并将其与 ("World") 连接,现在创建了一个值为 "HelloWorld" 的新对象,然后 JVM 将检查字符串常量池,如果它不存在则它将创建一个新对象并返回引用 String s2="HelloWorld" ,我们再次创建一个具有相同值的新字符串,然后它应该指向构建的对象。
    【解决方案3】:

    您正在创建两个对象 s1 和 s2 。所以当你这样做时

    s2==s1

    您正在比较这 2 个对象的引用,这将始终返回 false,因为这两个对象是分开的。

    如果比较字符串的内容,请尝试实现 .equals() 方法。

    s2.equals(s1)

    【讨论】:

    • 我说为什么他们不指向同一个对象/引用?
    • 当你做String s1='Hello'时,会在池中创建一个值为'Hello'的新对象,当你尝试创建String s2='HelloWorld'时,它会尝试查找对象是否已经存在于池中值为 'HelloWorld' 。由于它不存在,因此会创建一个新对象并将其分配给 s2。
    【解决方案4】:

    s1 和 s2 是指向 2 个不同地址的 2 个不同的引用。因此 s1==s2 将始终返回 false(因为地址不同)。

    【讨论】:

      【解决方案5】:

      这是因为 concat() 方法返回一个新的 String 对象

      public String concat(String str) {
          if (str.isEmpty()) {
              return this;
          }
          return StringConcatHelper.simpleConcat(this, str);
      }
      

      如果您改用“+”运算符,这将产生您预期的输出:

      String s1 = "Hello" + "World";
      String s2 = "HelloWorld";
      
      System.out.println(s1 == s2); // true
      

      希望这有助于您的理解, 但对于现实世界的使用,在比较字符串值时始终坚持使用 .equals():

      System.out.println(s1.equals(s2));
      

      【讨论】:

        猜你喜欢
        • 2018-10-28
        • 2018-01-08
        • 1970-01-01
        • 1970-01-01
        • 2017-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-13
        相关资源
        最近更新 更多