【问题标题】:The address of a string after concatenation [duplicate]连接后字符串的地址[重复]
【发布时间】:2019-08-11 05:48:03
【问题描述】:

我正在尝试查看字符串对象在 Java 中是如何工作的。

String value1 = "Good";
String value2 = "Good";
System.out.println(Integer.toHexString(value1.hashCode()));
System.out.println(Integer.toHexString(value2.hashCode()));
System.out.println(value1 == value2);

而且显示的是同一个地址

21f4dd

21f4dd

是的

我知道这两个变量指向存储在堆中的同一个对象。但是我在使用连接时被卡住了。

String value3 = "Bad";
System.out.println(Integer.toHexString(value3.hashCode()));
value3 += " enough";
System.out.println(Integer.toHexString(value3.hashCode()));
String value4 = "Bad enough";
System.out.println(Integer.toHexString(value4.hashCode()));
System.out.println(value3 == value4);

显示

103e5

c35f20b

c35f20b

连接后,有一个新的字符串对象,其值为“Bad enough”。我将此对象分配给 2 个变量,value3 和 value4 也打印它们的地址。

我的问题是 value3 和 value4 的地址是相同的,所以这意味着它们指向同一个对象,但是为什么 Java 在比较这两个变量时返回 false?

【问题讨论】:

  • 哈希码不是内存中的地址。快速阅读Wikipedia article 会澄清。
  • 另外,在 Java 中使用 == 运算符比较字符串是错误的。看来您不了解 Java 的基础知识,所以我强烈建议您阅读一本书。 Thinking Java 之类的东西。
  • 默认的hashCode实现返回内存地址,但是很遗憾String.hashCode被覆盖了。
  • 试试System.identityHashCode(value3)
  • @Sweeper 默认哈希码实现不返回内存地址。垃圾收集器可以在内存中移动 Java 对象,但它们的身份哈希码在移动后将保持不变。

标签: java string concat


【解决方案1】:

当您使用+ 进行连接时,java 内部使用StringBuilder。所以value3 += " enough"; 会被转换成行内的东西

value3 = new StringBuilder()
        .append(value3)
        .append(" enough")
        .toString();

这里的对象将在堆内存中创建。而在value4 的情况下,对象是在字符串池中创建的。

我建议你阅读:

JLS SE8 15.18.1:

实现可以选择执行转换和连接 一步避免创建然后丢弃中间体 字符串对象。提高重复字符串的性能 连接,Java 编译器可以使用 StringBuffer 类或 减少中间字符串对象数量的类似技术 通过评估表达式创建的。

Hashcode 和 equals 合约:https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()

两个字符串的哈希码相同,因为字符串覆盖了默认的hashCode 实现。它是根据 String 的内容计算的。

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

【讨论】:

  • 但真正的问题是为什么哈希码是一样的......
  • @CarlosHeuberger 哦,感谢您指出这一点。我已经编辑了我的答案。
【解决方案2】:

Strings的hashcode方法其实并不指向堆中的对象地址。

要获取实际地址,您可以使用 Unsafe API。不幸的是,据我所知,它没有正式记录。您可以尝试this获取对象堆上的实际内存地址。

【讨论】:

    猜你喜欢
    • 2018-10-15
    • 2019-08-14
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 2015-08-23
    • 2020-12-30
    • 2015-07-31
    • 2013-07-21
    相关资源
    最近更新 更多