为何修改StringBuilder会改变其哈希码?打印的标识哈希值为何不同?
疑问一:为何修改StringBuilder会改变它的哈希码?
首先要纠正一个关键认知:StringBuilder本身并没有重写Object类的hashCode()方法,它使用的是父类Object的默认实现。
Object的hashCode()(以及System.identityHashCode())返回的是对象的标识哈希值,这个值是基于对象在JVM中的唯一内存标识生成的,和对象的内容完全无关。也就是说,只要你操作的是同一个StringBuilder实例,哪怕你修改它的内容(append、insert等),它的哈希码都不会改变。
比如你可以跑这段代码验证:
StringBuilder sb = new StringBuilder("hello"); int initialHash = sb.hashCode(); sb.append(" everyone"); int modifiedHash = sb.hashCode(); System.out.println(initialHash == modifiedHash); // 输出true,因为是同一个实例
你之所以可能觉得修改内容会改变哈希码,大概率是混淆了String和StringBuilder的特性:String是不可变类,每次修改都会生成新的String实例,所以新实例的哈希码自然不同;但StringBuilder是可变类,所有修改操作都是在原实例上进行的,不会生成新对象,因此哈希码保持不变。
疑问二:为什么每次打印的标识哈希值都不一样?
看你的printBuilder方法里的这行代码:
StringBuilder build = new StringBuilder(dataBuild);
这行代码的作用是创建一个全新的StringBuilder实例,把传入的dataBuild的内容复制到这个新实例中。也就是说,每次调用printBuilder,你都会生成一个完全独立的StringBuilder对象。
而System.identityHashCode()的作用是返回每个对象实例的唯一标识哈希值——不同的对象实例,哪怕内容完全一样,这个值也几乎不可能重复。所以你每次打印的"address"(实际是标识哈希值)不一样,本质原因就是每次都在打印一个新创建的StringBuilder对象的标识哈希。
如果想打印原对象的标识哈希,你只需要去掉创建新实例的代码,直接使用传入的dataBuild即可:
private static void printBuilder(StringBuilder dataBuild){ System.out.println("data = " + dataBuild); System.out.println("length = " + dataBuild.length()); System.out.println("capacity = " + dataBuild.capacity()); int addressBuild = System.identityHashCode(dataBuild); System.out.println("address = " + Integer.toHexString(addressBuild)); }
这样修改后,三次打印的标识哈希值就会完全相同,因为你一直操作的是同一个StringBuilder实例。
另外提一句,你提供的输出里length和capacity的值看起来像是写反了(比如初始"hello"的length应该是5,capacity默认是16),可能是输出时的笔误,不过这不影响核心问题的解答。
内容的提问来源于stack exchange,提问作者rio

