参考网页

https://blog.csdn.net/isscollege/article/details/78398968

https://www.jianshu.com/p/9819eb48716a

疑问

String是final类,也就是不可变的。

String a = “abc”;

a = “xxx”;

实际上内存中“abc”、“xxx”都没变(每次赋值实际上都开辟了新的一块内存)。只是a的引用变了。

那么有个新的疑问,如下代码

String a = “abc”;

a = “abcde”;

可以看到“abcde”内容里包含“abc”,那么“abc”会不会被复用呢?就是“abcde”、“abc”起始地址会不会一样呢,如下图这样:“abcde”取的是5个char,“abc”取的是3个char,前三个char“abc”是一样的?

 

需要实际测试一下。

试验

JDK版本

C:\Users\lenovo>java -version

java version "1.8.0_161"

Java(TM) SE Runtime Environment (build 1.8.0_161-b12)

Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

测试代码

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class StringAddressTest {

    static final Unsafe unsafe = getUnsafe();
    static final boolean is64bit = true;

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InterruptedException {
        String a = "abc";
        String b = "abc";
        String c = "abcde";
        String d = "abcdefghigklmnopq";

        System.out.println(a == b);

//        System.out.println("======hashCode======");
//        System.out.println(a.getClass() + "@" + a.hashCode());
//        System.out.println(b.getClass() + "@" + b.hashCode());
//        System.out.println(c.getClass() + "@" + c.hashCode());
//        System.out.println(c.getClass() + "@" + d.hashCode());
//
//        System.out.println("======System.identityHashCode======");
//        System.out.println("a@" + System.identityHashCode(a) );
//        System.out.println("b@" + System.identityHashCode(b) );
//        System.out.println("c@" + System.identityHashCode(c) );
//        System.out.println("d@" + System.identityHashCode(d) );

        System.out.println("======Addresses======");
        printAddresses("a:", a);
        printAddresses("b:", b);
        printAddresses("c:", c);
        printAddresses("d:", d);

//        TimeUnit.SECONDS.sleep(10000);
    }

    public static void printAddresses(String label, Object... objects) {
        System.out.print(label + ": 0x");
        long last = 0;
        //获取偏移地址值
        int offset = unsafe.arrayBaseOffset(objects.getClass());
        //获取变量占用空间大小
        int scale = unsafe.arrayIndexScale(objects.getClass());
        switch (scale) {
            case 4:
                long factor = is64bit ? 8 : 1;
                final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
                System.out.print(Long.toHexString(i1));
                last = i1;
                for (int i = 1; i < objects.length; i++) {
                    final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
                    if (i2 > last) System.out.print(", +" + Long.toHexString(i2 - last));
                    else System.out.print(", -" + Long.toHexString(last - i2));
                    last = i2;
                }
                break;
            case 8:
                throw new AssertionError("Not supported");
        }
        System.out.println();
    }


    private static Unsafe getUnsafe() {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            return (Unsafe) theUnsafe.get(null);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

}

运行结果

true

======Addresses======

a:: 0x781eea450

b:: 0x781eea450

c:: 0x781eea480

d:: 0x781eea4b8

分析1

实际测试结果可见,

    String a = "abc";
    String b = "abc";

出现的是同样的结果

    String c = "abcde";
    String d = "abcdefghigklmnopq";

都是不同的结果了。

也就是说字符串没有被复用。

分析2

请注意JDK版本,是不是别的版本也是这样的结果?不知道。

 

02-02 07:51