String内部原理

描述

String内部是final修饰的char[]。下文定义方法获取String内部char[]的hashCode,验证不同的String对象内部char[]是否一致

代码

private static int showStringInternalCharArrayHashCode(String s) {
    Field value = null;
    try {
        value = String.class.getDeclaredField("value");
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }

    if (value != null) {
        value.setAccessible(true);
        try {
            return value.get(s).hashCode();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    return 0;
}
public static void main(String[] args) {

    String a = "abc";
    String b = "abc";
    String c = new String("abc");

    System.out.println("a.value:" + showStringInternalCharArrayHashCode(a));
    System.out.println("b.value:" + showStringInternalCharArrayHashCode(b));
    System.out.println("c.value:" + showStringInternalCharArrayHashCode(c));
    System.out.println("a:" + System.identityHashCode(a));
    System.out.println("b:" + System.identityHashCode(b));
    System.out.println("c:" + System.identityHashCode(c));

    // a.value:1595428806
    // b.value:1595428806
    // c.value:1595428806
    // a:1072408673
    // b:1072408673
    // c:1531448569
}

由结果看出变量a、b、c各自的内部char[]是同一个数组。a和b是因为从常量池中取出字符串,该字符串本就是同一个对象。c是因为String构造函数中将入参的char[]赋值给对象。可以从字节码中看出。

// #2定位到类常量池,在定位到字符串常量池中常量推送至操作数栈顶,
0: ldc           #2                  // String abc
// 存储变量到局部变量表下标1处
2: astore_1
3: ldc           #2                  // String abc
5: astore_2
// 堆中创建对象,对象引用推入栈顶
6: new           #3                  // class java/lang/String
// 复制栈顶元素
9: dup
// 常量池中常量推入栈顶
10: ldc           #2                  // String abc
// 调用构造函数初始化,参数对象引用和常量
12: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
// 对象创建完毕存储到局部变量表下标3处
15: astore_3
public static void main(String[] args) {

    String a = "abc";
    String b = "aabc".substring(1);

    System.out.println("a.value:" + showStringInternalCharArrayHashCode(a));
    System.out.println("b.value:" + showStringInternalCharArrayHashCode(b));
    System.out.println("a:" + System.identityHashCode(a));
    System.out.println("b:" + System.identityHashCode(b));

    b = b.intern();

    System.out.println("a.value:" + showStringInternalCharArrayHashCode(a));
    System.out.println("b.value:" + showStringInternalCharArrayHashCode(b));
    System.out.println("a:" + System.identityHashCode(a));
    System.out.println("b:" + System.identityHashCode(b));

//        a.value:1595428806
//        b.value:1072408673
//        a:1531448569
//        b:1867083167
//        a.value:1595428806
//        b.value:1595428806
//        a:1531448569
//        b:1531448569

}

由结果看出,变量a、b不是同一个对象,内部char[]也不是同一个数组。调用intern()后,a、b变成同一个对象了。

引用

https://dzone.com/articles/java-string-tutorials
https://dzone.com/articles/string-memory-internals

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文假定你对C/C++的string语法已经有基本的了解。 如果你对C++的string的内部实现原理不了解的话,...
    铁甲万能狗阅读 7,923评论 0 8
  • 最全的iOS面试题及答案 iOS面试小贴士 ———————————————回答好下面的足够了-----------...
    zweic阅读 2,724评论 0 73
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,421评论 0 2
  • 所有知识点已整理成app app下载地址 J2EE 部分: 1.Switch能否用string做参数? 在 Jav...
    侯蛋蛋_阅读 2,514评论 1 4
  • 一. Java基础部分.................................................
    wy_sure阅读 3,839评论 0 11