1.String类
字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。
String对象实现了Serializable接口,说明String对象可以串行化(在网络中进行传输),同时实现了Comparable接口,说明String对象可以进行比较🎁
String是个final类,这代表它是不可被继承的
String的本质依然是char数组(或者byte数组,要看JDK的版本),通过源码我们可以轻松的得知:
// JDK1.9及之后的版本,String的字符串内容保存在一个叫做value的byte数组中 @Stable private final byte[] value; // 注意这里的value数组是一个final类型,这代表它是不可以被修改的,这里指的是value的地址不能发生修改,而并非value数组里的值
总结:jdk1.8及以前String使用的是char数组,jdk1.9及以后使用的是byte数组。🎈
为什么改成byte数组了呢?🙌
因为开发人员发现人们使用的字符串值是拉丁字符居多而之前使用的char数组每一个char占用两个字节而拉丁字符只需要一个字节就可以存储,剩下的一个字节就浪费了,造成内存的浪费,gc的更加频繁。因此在jdk9中将String底层的实现改为了byte数组。
2.StringBuffer
概述
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。这极大的节省了资源的使用
StringBuffer的本质依然是char数组(或者byte数组,要看JDK的版本)但是和String不同的是,该数组不是final类型的🎈和String类一样,StringBuffer类也是final类型,代表它不能被继承!🤷♂️
String VS StringBuffer
String是不可变的对象,因此每次在对String类进行改变的时候都会生成一个新的String对象,然后将指针指向新的String对象,所以经常要改变字符串长度的话不要使用String,因为每次生成对象都会对系统性能产生影响,特别是当内存中引用的对象多了以后,JVM的GC就会开始工作,性能就会降低
使用StringBuffer类时,每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用,所以多数情况下推荐使用StringBuffer,特别是字符串对象经常要改变的情况
String对象的速度并不会比StringBuffer对象慢的情况:
String s1 = "This is only a" + " simple" + " test"; StringBuilder sb = new StringBuilder("This is only a").append(" simple").append(" test");
生成 String s1对象的速度并不比 StringBuffer 的 sb慢。其实在Java Compiler里,自动做了如下转换:
String s2 = "This is only a"; String s3 = " simple"; String s4 = " test"; String s1 = s2 + s3 + s4;
这时候,Java Compiler会规规矩矩的按照原来的方式去做,String的 + 操作利用了StringBuilder(或StringBuffer)的append方法实现
StringBuffer三种构造器初始化
// 创建一个大小为16的char[] 数组,用于存放字符内容 StringBuffer stringBuffer = new StringBuffer(); // 指定char[]容量大小 StringBuffer stringBuffer1 = new StringBuffer(100); // 通过给一个string创建stringbuffer,初始容量为字符串长度 + 16 StringBuffer dahezhiquan = new StringBuffer("dahezhiquan");
String和StringBuffer的转换
String --> StringBuffer😀
// String --> StringBuffer String str = "hello"; // 方法一:通过构造器 StringBuffer stringBuffer2 = new StringBuffer(str); // 方法二:通过append StringBuffer stringBuffer3 = new StringBuffer(); stringBuffer3.append(str);
StringBuffer --> String😁
// StringBuffer --> String StringBuffer stringBuffer4 = new StringBuffer("lsp"); // 方法一:通过toString方法 String s = stringBuffer4.toString(); // 方法二:使用构造器 String s1 = new String(stringBuffer4
3.StringBuilder
概述
一个可变的字符序列,此类提供一个与StringBuffer兼容的API,但不保证同步(不是线程安全的),用在字符串缓冲区被单个线程使用的时候,如果可能建议优先使用该类,因为在大多数的时候,它比StringBuffer要快
StringBuilder类是final类型,不能被继承!StringBuilder的本质依然是char数组(或者byte数组,要看JDK的版本),该数组不是final类型🎈
常用API
StringBuilder append(String str):
添加一部分内容
StringBuilder stringBuilder = new StringBuilder("wode"); stringBuilder.append("shijie"); System.out.println(stringBuilder); // wodeshijie
void setCharAt(int i, char c):
将第i个代码单元设置为c
StringBuilder stringBuilder = new StringBuilder("wode"); stringBuilder.setCharAt(0, 't'); System.out.println(stringBuilder); // tode
StringBuilder insert(int offset, String str):
在offset位置插入一个字符串
StringBuilder stringBuilder = new StringBuilder("wode"); stringBuilder.insert(1, "dada"); System.out.println(stringBuilder); // wdadaode
StringBuilder delete(int startIndex, int endIndex):
删除偏移量从startIndex到-endIndex-1的代码单元
StringBuilder stringBuilder = new StringBuilder("wodeshijie"); stringBuilder.delete(1, 3); System.out.println(stringBuilder); // weshijie
4.总结
如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer
不要使用String类的”+”来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则
相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。因此:除非确定系统的瓶颈是在 StringBuffer 上,并且确定你的模块不会运行在多线程模式下,才可以采用StringBuilder;否则还是用StringBuffer
去留无意,闲看庭前花开花落;宠辱不惊,漫随天外云卷云舒。🥞