目录
一、引入
插入方法currentTimeMillis()的介绍
二、详细介绍
1.String
2.StringBuilder
①StringBuilder与String的区别
②StringBuilder的常用方法
3.StringBuffer
拓展(缓冲区)
三、对比
1.⭐String,StringBuffer,StringBuilder三种有什么区别(概括):⭐
详细介绍版本:
①不可变性:
②线程安全性:
③性能:
④使用场景:
四、扩展
1.内存页⭐
2.⭐弱类型语言⭐
一、引入
在介绍String,StringBuffer,StringBuilder这三种之前,先通过一段代码来引进初步概念:
一下提供了两种字符串拼接的方法,一种只是原始String拼接,另一种则是借助可变的字符序列StringBuilder的append()方法实现字符串拼接,并计算两者运算之间时间差距。
public static void main(String[] aa) {long starttime=System.currentTimeMillis();String str="";for(int i=0;i<100;i++){str+="a";//原始字符串拼接方法①}StringBuilder str2=new StringBuilder();for(int i=0;i<100;i++){str2.append("a");//append()方法拼接的速度远远大于上面的原始拼接②}System.out.println(str);System.out.println(str2);long endtime=System.currentTimeMillis();long timeall=endtime-starttime;System.out.println("总计花费时间:"+(timeall));}
【注:上述计算时间差应用的方法是currentTimeMillis()】
插入方法currentTimeMillis()的介绍
currentTimeMillis()是Java中的一个静态方法,属于System类;该方法返回自1970年1月1日午夜(协调世界时)以来经过的毫秒数(注意返回类型是long类型的)。
所以可以用于以下场景:
- 时间戳:currentTimeMillis()返回的时间戳常用于生成时间相关的数据,例如记录日志时间、生成时间戳等。
- 性能测试:通过在代码执行前后调用currentTimeMillis(),可以测量代码段的执行时间。例如,测量一段代码的执行时间,可以在代码执行前后分别调用currentTimeMillis(),然后计算两者之差。
- 线程控制:在多线程编程中,currentTimeMillis()可以用来控制线程的休眠时间,或者用于控制屏幕刷新的频率等。
- 生成唯一文件名:通过结合当前时间生成文件名,可以确保文件名的唯一性,避免重名。
基于上述时间戳的功能,在这段代码中,记录开始时间与结束时间求得时间差。
回归正传,上述代码的运行①和②时间差中,①String花费的时间远远超过②StringBuilder,接下来开始介绍其中的缘由。
二、详细介绍
1.String
String是Java中表示文本的类,它是不可变的,这意味着一旦创建了String对象,就不能更改它的内容。
2.StringBuilder
StringBuilder是一个可变的字符序列,提供了一系列方法来构建和修改字符串,而不需要创建新的字符串对象,从而提高了字符串操作的效率。在Java中,当需要在循环中构建字符串时,使用StringBuilder可以显著提高性能,因为它避免了在每次循环中创建新的字符串对象。(打破了String类型每次更改都需要申请新的空间的问题)
①StringBuilder与String的区别
- 性能:StringBuilder在单线程环境下比String更高效,因为它允许在原有字符串的基础上进行修改,避免了创建新的字符串对象。
- 线程安全:StringBuilder不是线程安全的,而String和StringBuffer是线程安全的。如果多个线程需要访问同一个StringBuilder对象,可能会导致数据不一致。
②StringBuilder的常用方法
- append():将指定的字符串添加到StringBuilder对象的末尾【引入中所用】。
- insert():在指定位置插入字符串。
- delete():删除指定位置的字符。
- reverse():反转StringBuilder中的字符序列。
- capacity():设置或获取StringBuilder的容量。
3.StringBuffer
StringBuffer是StringBuilder类的前身,是一个字符缓冲区,用于存储和操作字符串。与String类不同,StringBuffer的对象是可以扩充和修改的,它使用缓冲区来存储字符串数据。这意味着,当需要频繁修改字符串内容时,使用StringBuffer会更加高效。
StringBuffer通过使用缓冲区来存储字符串数据。与String类不同,StringBuffer的内容是可以改变的。在StringBuffer中,可以使用append()方法进行字符串的连接操作,这使得它非常适合用于需要频繁修改字符串内容的场景。
拓展(缓冲区)
Buffer:一般名字类里带Buffer的,就是缓冲区,速度和节省空间的能力都很优秀,并不局限于StringBuffer。
三、对比
1.⭐String,StringBuffer,StringBuilder三种有什么区别(概括):⭐
- StringBuffer,StringBuilder速度远远高于String;
- StringBuilder多线程并发操作不安全和StringBuffer多线程并发操作下安全;
- StringBuffer里面加了锁,速度稍微慢一点点;
详细介绍版本:
①不可变性:
- String:String对象是不可变的,一旦创建就不能被修改。任何对字符串的操作都会生成一个新的String对象。
- StringBuffer和StringBuilder:这两个类都是可变的,可以在原始字符串上进行修改,无需创建新的对象。
②线程安全性:
- String:是线程安全的,因为它的方法在内部使用了同步机制,适用于多线程环境。
- StringBuffer:也是线程安全的,适用于多线程环境。
- StringBuilder:不是线程安全的,适用于单线程环境。
③性能:
- String:由于每次操作都会生成新的对象,执行速度较慢,且内存使用效率较低。
- StringBuffer:执行效率较慢,但线程安全。
- StringBuilder:执行效率较高,但线程不安全。
④使用场景:
- String:适用于少量的字符串操作或在单线程环境中使用。
- StringBuffer:适用于多线程环境中的字符串操作,虽然效率较低,但保证了线程安全。
- StringBuilder:适用于单线程环境中的大量字符串操作,因为其执行效率较高。
四、扩展
1.内存页⭐
CPU与内存交换数据太过频繁,但是同一时间只能通过如下一条线路进行交换,为了解决这种问题提高效率,引进了内存页。
内存页的大小由特性决定:内存页越大,读取的次数就越少,即读取速度就越快,同时内存页越大,浪费的空间就越多,为了中和读取速度和空间浪费这两种关系,最终选定4KB为一个内存页的存储空间。(每个内存页占据4KB)
为此,操作系统所能调度的最小分配单元是4KB。
每个内存页对外只有一个总地址,即如下箭头所指的开头位置(即:每个内存页只能属于一个变量,不能属于其他变量,唯独填入数组的情况下,一个内存页可以好几个同类型的变量使用,所以数组的使用可以节省内存)
即:如下
所以,int a=9;看似只需要32bit的内存,实际上会被分配4KB的内存。
2.⭐弱类型语言⭐
e.g Python,php,js等不区分数组类型,但是弱类型语言最终是要被转化成C语言的,因为C语言是区分类型的,转化过程中还是需要分类的,十分消耗内存页,消耗内存十分大。
5.有了以上概念,就可以接着分析String,由于String的不可变特性,导致每次操作都会去申请新的空间,对内存的消耗十分巨大。
改善方法:更改本地、缓冲区(Buffer)