String类型深度剖析

1、底层结构
  • jdk1.8:private final char[] value;
  • jdk1.9:private final byte[] value;
2、String的不可变性
  • 字符串常量池里不能存在相同的字符串
  • 字符串一旦被赋值则不可修改,后面对字符串的任何修改都是重新new了一个字符串对其做修改
  • String的String Pool是一个固定大小的HashTable
    • jdk1.6,StringTable默认是1009,可以设置的范围没有限制
    • jdk1.7,StringTable默认是60013,可以设置的范围没有限制
    • jdk1.8,StringTable默认是60013,可以设置的最小范围是1009
    • 通过-XX:StringTableSize设置StringTable的大小
3、字符串拼接操作
  • 常量与常量的拼接结果在常量池,原理是编译期优化
  • 常量池中不会存在相同内容的常量
  • 只要其中有一个是变量,结果就在堆中(StringPool之外的堆中),变量拼接的原理是StringBuilder
  • 如果拼接的结果调用Intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址
public static void main(String[] args) {
        String s1 = "java";
        String s2 = "python";
        String s3 = "javapython";
        String s4 = "java"+"python";
    //如果拼接符号前后出现了变量,则相当于在堆空间中new String(),具体的字符串内容为拼接的结果
        String s5 = s1+"python";
        String s6 = "java"+s2;
        String s7 = s1+s2;
        System.out.println(s3==s4);//true
        System.out.println(s3==s5);//false
        System.out.println(s3==s6);//false
        System.out.println(s3==s7);//false
        System.out.println(s5==s6);//false
        System.out.println(s5==s7);//false
        System.out.println(s6==s7);//false
    //如果拼接的结果调用Intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址
    	String s8 = s6.intern()
        System.out.println(s3==s8);//true   
    }
4、StringBuilder.append()和String字符串拼接比较
public static void methodString(int n) {
    String s = "";
    for (int i = 0; i < n; i++) {
        s = s + "a";
    }
}

public static void methodStringBuilder(int n) {
    StringBuilder s = new StringBuilder();
    for (int i = 0; i < n; i++) {
        s.append("a");
    }
}

public static void main(String[] args) {
    int n = 100000;
    long start1 = System.currentTimeMillis();
    methodString(n);
    long end1 = System.currentTimeMillis();
    System.out.println("methodString:" + (end1 - start1)); //methodString:3454
    System.out.println("---------------------");
    long start2 = System.currentTimeMillis();
    methodStringBuilder(n);
    long end2 = System.currentTimeMillis();
    System.out.println("methodStringBuilder:" + (end2 - start2));  //methodStringBuilder:1
}

通过上面测试比较,可以发现StringBuilder比String要快得多

  • StringBuilder.append()只会创建一个StringBuilder对象,String字符串拼接会创建多个StringBuilder对象和String对象
  • String字符串拼接会创建多个StringBuilder对象和String对象产生,会占用大量内存,如果要进行GC,会花费额外的时间
5、String.intern()的使用
  • intern()会判断常量池里有没有这个字符串,有的话这该变量的引用地址返回,没有的话在常量池里添加该字符串并返回其引用地址
  • String s = new String(“ab”)创建了几个对象? -----字符串常量池中有"ab"
    • 两个,一个是new关键字在堆里创建的,另一个在字符串常量池中,字节码指令:ldc
  • String s = new String(“a”) + new String(“b”)创建了几个对象? -----字符串常量池中没有"ab"
    • 6个,对象一:堆中的StringBuilder,对象二:堆中的"a",对象三:字符串常量池中的"a",对象四:堆中的"b",对象五:字符串常量池中的"b"
    • 深入剖析:对象六:堆中的new String(“ab”),toString()方法的调用,底层虽然是new String(),但是只会在堆中创建对象,不会在字符串常量池中生成字符串
  • 对于程序中大量存在的字符串,尤其其中存在很多重复的字符串时,使用String.intern()方法可以节省内存空间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值