Java String Equality – s1 == s2 but FieldOffset is Different

java

As I am studying java, I have learned that the proper way to compare 2 Strings is to use equals and not "==". This line

static String s1 = "a";
static String s2 = "a";
System.out.println(s1 == s2);  

will output true because the jvm seems to have optimized this code so that they are actually pointing to the same address. I tried to prove this using a great post I found here

http://javapapers.com/core-java/address-of-a-java-object/

but the addresses don't seem to be the same. What am I missing?

import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class SomeClass {
    static String s1 = "a";
    static String s2 = "a";
    public static void main (String args[]) throws Exception {
        System.out.println(s1 == s2); //true

        Unsafe unsafe = getUnsafeInstance();
        Field s1Field = SomeClass.class.getDeclaredField("s1");
        System.out.println(unsafe.staticFieldOffset(s1Field)); //600

        Field s2Field = SomeClass.class.getDeclaredField("s2");
        System.out.println(unsafe.staticFieldOffset(s2Field)); //604

    }

    private static Unsafe getUnsafeInstance() throws SecurityException, 
        NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeInstance.setAccessible(true);
        return (Unsafe) theUnsafeInstance.get(Unsafe.class);
    }
}

Best Answer

I think you're confused on what staticFieldOffset is returning. It's returning the offset of the pointer to the String instance, not the address of the String itself. Because there are two fields, they have different offsets: ie, two pointers, which happen to have the same value.

A close reading of the Unsafe javadoc shows this:

Report the location of a given field in the storage allocation of its class. Do not expect to perform any sort of arithmetic on this offset; it is just a cookie which is passed to the unsafe heap memory accessors.

In other words, if you know where the actual Class instance is in memory, then you could add the offset returned by this method to that base address, and the result would be the location in memory where you could find the value of the pointer to the String.

Related Question