4

L's code is very simple

public class L {
}

public class Synchronized1 {
    public static void main(String[] args) {
        L l=new L();
//       System.out.println(l.toString());
       System.out.println(ClassLayout.parseInstance(l).toPrintable());
    }
}

Uncommenting, running the code again will result in different results, or two completely different results. I want to know what is the cause of this result? Not just calling toString() affects the result, but calling other methods on the object also affects the result such as hashCode()

toString() After the comments

dengshuo
  • 59
  • 5
  • 1
    That's actually an interesting question, where I might have a hint (I'll look to find the reference): Calling hashCode() will use a field in the layout, so it's result is the same over several invocations. – Johannes Kuhn Sep 25 '19 at 09:59
  • 3
    I found the article I read about that: https://srvaroa.github.io/jvm/java/openjdk/biased-locking/2017/01/30/hashCode.html – Johannes Kuhn Sep 25 '19 at 10:01
  • @T.J.Crowder Not needed in this example. L could be Object, and you would see the same behavior. – Johannes Kuhn Sep 25 '19 at 10:02
  • @T.J.Crowder I could have told you that `hashcode()` and `toString()` was not implemented. Read the article I posted, it will explain what is going on. – Johannes Kuhn Sep 25 '19 at 10:11
  • @JohannesKuhn Can you also tell us what the two ClassLayouts that are being printed are? Thank you. – Thilo Sep 25 '19 at 10:13
  • 1
    @JohannesKuhn - The point is to have a self-contained question answerable on the site. – T.J. Crowder Sep 25 '19 at 10:14
  • 2
    Note that the parts of the hashcode appear in the values : 3f 99 bd 52 . – Arnaud Sep 25 '19 at 10:25
  • 3
    What you are seeing is consistent with the article linked to by @JohannesKuhn: If you call `hashCode` for the first time on an object (using the default hashcode implementation), it stores that hashCode (the instance identity hashcode) in the object header. – Thilo Sep 25 '19 at 10:25

1 Answers1

4

Your empty class class L uses the default toString() inherited from class Object.

The default toString() invokes hashCode().

And as you have already seen, hashCode() also seems to affect the header of the object.

So, in essence, the problem can be restated as "Why does calling hashCode() alter the header of my object?"

As others have already pointed in the comments, this is happening because in the particular JVM implementation that you are using, the hashCode of an object is computed the first time hashCode() is invoked, and then it is cached in the header, so that subsequent calls to hashCode() can just return the cached value, without having to re-compute it again.

Besides performance, there may be an even more important reason for doing this.

Depending on how the JVM that you are using computes hashcodes, there may be randomness involved in the computations, or there may be an ever-incrementing number seed, so it may be that subsequent attempts to reproduce the hashcode of an object would have no means of generating the exact same value as the first computation. This means that the very first computation must determine what the hashcode value will be forever after.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142