【问题标题】:Java String InstantiationJava 字符串实例化
【发布时间】:2017-10-22 15:20:54
【问题描述】:

为什么这段代码返回的是“false”而不是“true”:

package com.company;


public class Main {

    public static void main(String[] args) {

        String fullName = "Name Lastname";
        String name = "Name ";
        String lastName = "Lastname";
        String firstNamePlusLastName = name + lastName;

        System.out.println(fullName == firstNamePlusLastName);

    }
}

如果我没记错的话:

String firstNamePlusLastName = name + lastName;

应该创建一个指向内存中现有地址(字符串池)的字符串,因为我们已经声明了一个值为:“Name Lastname”的字符串,它不应该被自动嵌入到字符串池中并且不应该输出为“真”,因为我们在字符串池中已经有与 String firstNamePlusLastname 具有相同值的字符串?

编辑:

我知道在测试两个字符串的内容是否相等时我应该使用 .equals() 方法,但我不想在上面的示例中这样做,我确实想测试引用是否相等,并且基于 Java我在上面的代码中比较的两个字符串应该相等,但它们不是,它们应该指向内存中的相同地址,因为它们具有相同的内容,并且两个字符串都不是使用“new”关键字创建的。我想知道为什么会这样。

【问题讨论】:

  • 你必须使用equals来比较两个字符串对象。
  • 我相信 JLS 坚持认为这是错误的。如果您将参考文献定为最终版本,那就另当别论了。
  • @KevinO:不,它也可以是其他字符串常量的串联......并且用字符串常量初始化的静态最终字段,或者用字符串常量初始化的最终局部字段也是常量表达式。所以是的,在某个地方总会有一个字符串文字(除非一切都是空的),但这不是一回事。
  • 我的answer 怎么样,先生。

标签: java string reference pool


【解决方案1】:

在编译时创建字符串常量池。当您连接字符串 literals / final 变量 / final 字段(final 参数除外)时,它仅使用池中的字符串,对于示例:

连续文字

String fullName = "Name Lastname";
String firstNamePlusLastName = "Name " + "Lastname";

System.out.println(fullName == firstNamePlusLastName);// true

连接最终变量

String fullName = "Name Lastname";
final String name = "Name ";
final String lastName = "Lastname";
String firstNamePlusLastName = name + lastName;

System.out.println(fullName == firstNamePlusLastName);//true

【讨论】:

  • 不只是任何final - 它们必须是final locals或静态final字段,并且必须使用常量表达式进行初始化。
  • @JonSkeet 我想我需要修复它,:)。因为final 参数没有。非常感谢。
  • @JonSkeet:不需要限制变量的类型。规范说,任何使用编译时常量(并且是原始类型或String)初始化的final 变量都是编译时常量。这会自动排除参数,因为参数不能有初始值设定项。但是,这意味着字段不必必须是static 才能成为编译时常量。 (虽然,常量非static 字段是浪费内存......)
  • @Holger:很有趣,是的。
【解决方案2】:

因为你必须使用.equals() 来字符串

fullName.equals(firstNamePlusLastName)

== 测试引用相等(它们是否是同一个对象),意思完全一样,甚至是相同的引用。

.equals()指的是一个对象的equals实现,这意味着,对于字符串,如果它们具有相同的字符顺序相同。

考虑一下:

    String a = new String("a");
    String anotherA = new String("a");
    String b = a;
    String c = a;

a == anotherA -> False;
b == a -> True
b == c -> true
anotherA.equals(a) -> True

【讨论】:

  • 是的,如果你创建一个这样的字符串: String someString = "Some content";然后你像这样创建另一个: String anotherString = "Some content";并用“==”测试是否相等,它返回true,因为第一个字符串被JVM隐式实习,但上面的例子不是这样,我只是想知道为什么。
  • 我认为这仍然不能回答问题。 OP 想知道为什么在编译时没有完成连接,然后将结果添加到字符串池中。
  • @Damian Lattenero,正如 Jon Skeet 和 KevinO 所证实的那样,使用 Dawood 是正确的。
【解决方案3】:

String literals 被保留。当您通过任何不是文字的方法(调用new String()、从输入读取、连接等)创建字符串时,它不会被自动实习。当您调用String firstNamePlusLastName = name + lastName; 时,您将namelastName 连接起来创建了一个新字符串。这不是文字,而且您没有调用 intern,因此该字符串不会添加到字符串池中。

【讨论】:

  • 不,字符串 constants 被保留。从 3.10.5 开始:“这是因为字符串文字 - 或者更一般地说,作为常量表达式值的字符串(第 15.28 节) - 是“内部”的,以便使用 String.intern 方法共享唯一实例。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-23
相关资源
最近更新 更多