关于String的一些思考

为什么要设定不可变

已知:底层用char数组,final关键词修饰所以不可变

private final char value[];
final 使得引用地址不可变,但value数组的值可以改变
private 限制了访问域,只能String对象自身可以修改
字符串String对外界的不可变是由于 final 和 private
不可变意味着:你对一个字符串变量进行修改时其实是产生一个新的字符串

不可变对String的影响

字符串的修改:由于java语法的特性,我们在申请一个新的数组时需要给定长度,那么我们在创建一个字符串时也就创建对应长度的char数组。正常按逻辑走,对于字符串的修改,如果是与原长度相等,那么自然好,只需要修改对应下标的字符char,但如果小于或超过给定的长度,那么就需要重新申请一个新长度的char数组,即需要通过判断来选择不同方式达到修改目的。
而String底层的不可变性质使得修改通常情况下等同于新增。

为什么说通常情况下呢
在说明原因前,我们先来了解一下JVM字符串常量池

  1. JVM 字符串常量池: 位于内存结构中的堆,通俗讲,是一个承载了很多字符串常量的池子
    当有多个变量指向同样的字符串常量,就算其中有字符串变量要修改了也只是改变了指向或者新增了一个字符串常量,不会影响除此之外其他变量的使用,实现线程安全
    如果该字符串常量不使用,也有相应的垃圾回收机制去回收,也不会造成空间的浪费

可以理解为是一个实现共享的池子,如果该字符串对应的内容已经存在于常量池,那么就不需要重新申请一个。
不论是String类型变量还是常量,底层指向的字符串内容位于常量池中 – 常量池使得修改不一定等同于新增,因而笔者描述为通常情况下。

简单梳理下因果:

JVM 字符串常量池 -> 实现共享 -> 实现线程安全
JVM常量池需要其底层不可变 == final & private -> 实现不可变

不可变的好处体现在:
正因为字符串的不可变性质促成了常量池,才能达到一个字符串的修改不会影响其它字符串的效果,从而实现线程安全

坏处:修改 == 新增,或许有人觉得在长度相等的情况下没必要重新申请新的数组空间;这一点一定程度上共享弥补了,共享可以去节省一定的内存空间,并且实现了不会影响其他字符串变量的使用,且无需比较字符串的长度,因而利大于弊

当然也正因这个坏处,如果需要经常修改字符串内容,最好就不要使用String类型了

String 拼接操作为什么会比StringBuilder耗时
String的拼接过程:实践上是使用StringBuilder的append()方法,再tostring()返回一个字符串,因而相比StringBuilder更耗时

顺嘴提一句:
StringBuilder 与 StringBuffer都是可变对象,前者线程不安全,效率高一些,后者线程安全,效率相对慢一些。

JVM常量池

实际上,JVM不只是含有字符串常量池,对应Integer(-128 – 127)、Short(-128 – 127)Char(0-127)等数值区间限制的常量池

//这是截取Short包装类底层关于常量池部分源码
private static class ShortCache {
        private ShortCache(){}

        static final Short cache[] = new Short[-(-128) + 127 + 1];

        static {
            for(int i = 0; i < cache.length; i++)
                cache[i] = new Short((short)(i - 128));
        }
    }
//自动装箱源码
public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }

验证常量池的存在

 		Short a = 3;//jvm 自动装箱 相当于 Short a = Short.valueOf((short)3)
        Short b = 127;
        Short c = a.shortValue();
        Short d = b.shortValue();
        Short e = 128;
        Short f = e.shortValue();
        System.out.println(a == c);// true
        System.out.println(b == d);// true
        System.out.println(e == f);// false

注:这是笔者的一点拙见,如若有不对的情况欢迎评论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值