2

I'm trying to see how string object works in 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);

And it shows the same address

21f4dd

21f4dd

true

I know that these 2 variables point to the same object which is stored in heap. But I'm stuck when using concatenation.

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);

It shows

103e5

c35f20b

c35f20b

false

After concatenation, there is a new string object whose value is "Bad enough". I assign this object to 2 variables, value3 and value4 also print their address.

My question is that the address of value3 and value4 are the same, so it means they point to the same object but why Java return false when comparing these 2 variables?

Community
  • 1
  • 1
  • 4
    Hash code is not the address in memory. A quick read of the [Wikipedia article](https://en.wikipedia.org/wiki/Hash_function) would clarify. – Alexander Solovets Aug 11 '19 at 05:51
  • 2
    Also, it's wrong to compare strings in Java using `==` operator. It looks like you don't know the fundamentals of Java, so I highly recommend to read a book. Something like _Thinking Java_. – Alexander Solovets Aug 11 '19 at 05:53
  • The default `hashCode` implementation returns the memory address, but `String.hashCode` is overridden, unfortunately. – Sweeper Aug 11 '19 at 05:57
  • try `System.identityHashCode(value3)` – user85421 Aug 11 '19 at 05:59
  • In Java `String.hashCode()` is calculate as `s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]` where s[i] is the ith character of the string, n is the length of the string. It isn't returning a memory address. – Yoshikage Kira Aug 11 '19 at 06:06
  • 2
    @Sweeper The default hashcode implementation does not return a memory addresses. Java objects can be moved around in memory by the garbage collector, but their identity hashcode will remain the same after such a move. – Mark Rotteveel Aug 11 '19 at 06:11

2 Answers2

2

When you use + for concatenation, java internally uses StringBuilder. So value3 += " enough"; will be converted to something around the line

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

here object will be created in the heap memory. Whereas in the value4 case the object is being created in String Pool.

I suggest you to read:

JLS SE8 15.18.1:

An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.

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

Hashcode of both the Strings is the same because String overrides default hashCode implementation. It is calculated on the content of 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;
    }
Govinda Sakhare
  • 5,009
  • 6
  • 33
  • 74
1

The hashcode method of Strings actually doesn't point to the object address in the heap.

To obtain the actual address you can use the Unsafe API. Unfortunately, as far as I know, it isn't officially documented. You can try this to obtain the actual memory address on heap of an object.

NathanPB
  • 685
  • 1
  • 7
  • 22