好文分享第三天——String、StringBuffer、StringBuilder的区别

Srting、StringBuffer、StringBuilder

1.String:它的类和类中的方法都是带final修饰符的,证明是一个Immutable(不可变)的类,它不可变的属性使得它天然的线程安全。
不可变的作用是将一个对象被多线程分享,并且访问频繁时,可以省略同步和锁等待的时间,从而大幅度的提高系统的性能。不可变模式是一个提高多线程程序的性能,降低多线程程序复杂度的设计模式。
当然线程安全带来的是性能上的开销增加,所以当字符串的操作在项目中存在较多使用场景时,建议不使用Srting。
针对常量池的优化:当两个String对象拥有相同的值时,他们只引用常量池中的同一个拷贝。当同一个字符串反复出现时,这个技术可以大幅度节省内存空间。
2.StringBuffer:Java1.5后添加的,提供append、add方法,把字符串添加到已有序列的末尾或者指定位置。
同时它也是一个线程安全的类,这为它的使用带来了额外的性能开销,所以在非特定的线程安全要求的情况下,一般都使用它的后继者StringBuilder。
线程安全的实现方式也很简单,就是在各种修改数据的方法上加上synchronized关键字实现,简单粗暴。在这里可读性才是最重要的,而无需考虑synchronized的性能,安全可靠才是最重要的。
3.StringBuilder:基本功能和StringBuffer相同,但是去除了StringBuffer中线程安全这部分,导致性能方面相较StringBuffer有较大提升。

String的创建原理

String的使用频率是非常高的,所以我们频繁的创建产生大量String对象对性能影响还是很大的。所以String引入了字符串常量池。
字符串常量池的运行机制:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接从池中刚查找到的对象引用;如果没有则新建字符串对象,返回对象引用,并且将新创建的对象放入池中。但是,通过new方法创建的String对象是不检查字符串池的,而是直接在堆区或栈区创建一个新的对象,也不会把对象放入池中。上述原则只适用于通过直接量给String对象引用赋值的情况。
String str1 = "abc";  //查找常量池,没有就放入常量池
String str2 = new String("abc");  //通过new赋值方式,不放入常量池
String提供了inter()方法,调用该方法时,如果常量池中包括了一个等于此String对象的字符串(由equals方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并且返回此池中对象的引用。

应用场景

在字符串基本不怎么变化,且对拼接等操作比较少、对字符串常量声明的,就使用String。避免使用”+”操作,这样耗费空间的同时又效率低
频繁使用字符串的拼接、替换、删除等操作的,同时在多线程环境下(因为考虑线程需要安全),尽量使用StringBuffer。如http参数解析封装、xml解析。
频繁使用字符串的拼接、替换、删除等操作的,同时在单线程环境下(因为无需考虑线程安全),尽量使用StringBuilder。如json串拼接和sql语句的拼接

深入思考

1.为了实现修改字符序列的目的,StringBuffer 和 StringBuilder 底层都是利用可修改的char(JDK 9 以后是 byte)数组,二者都继承了AbstractStringBuilder,里面包含了基本操作,区别仅在于最终的方法是否加了synchronized。
2.通过看了源码,char数组的默认长度是16,但是如果在可控范围内定义字符串,尽量先定义好长度,否则不断扩容对性能开销也挺大的

这里写图片描述

StringBuilder stringbuilder = new StringBuilder(20);  
通过源码发现,如果传入的是字符串则会自动添加16的长度,传入char类型也是
3.JDK9为什么将char数组换成了bytes数组

总的说还是密度问题,因为char占的是两个byte,造成一定的浪费,同时紧凑的字符串带来的优点是:更小的内存占用、更快的操作速度。但是在字符串最大长度方面就有所不足,byte数组在同样数组长度下,存储能力退化了一倍,一个char两个byte,容量依然没变,所以char数组可以存32个byte单位,byte数组最多16个。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页