0、思考
我们都知道真正修改一个String的内容是很难的,而我们平常却可以通过‘+=’来拼接字符串
public static void main(String[] args) { String str = new String("Hello"); str += " World"; System.out.println(str); }
这是为什么呢?我们接着往下看。
1、讲解String拼接字符串原理
Ⅰ底层字符接实现逻辑
我们来看一下上述代码的底层实现逻辑
我们发现,当我们执行 “str += " World";”时底层其实走四步
先创建一个StringBuilder对象,并调用无参数的构造方法。
StringBuilder对象调用append方法,把str内部 “Hello” 拼接到内部。
StringBuilder对象再次调用append方法,把 " World" 拼接到内部。
最后StringBuilder对象调用toString方法,把拼接好的字符串传给str。
"":表示构造方法
()V:表示无参数的构造方法
上述代码其实就等同于
public static void main(String[] args) { String str = new String("Hello"); StringBuilder sb = new StringBuilder(); sb.append(str); sb.append(" World");//拼接字符串 str = sb.toString(); System.out.println(str); //输出Hello World }
所以我们每次拼接字符串时,都会创建一个对象进行该操作,而非在String内部进行。
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
StringBuilder变为String: 调用toString()方法
Ⅱ使用不同方法拼接字符串事件比较
我用两种方法拼接字符串,我们来看一下各种运行时间
public static void main(String[] args) { //普通方法拼接 long start = System.currentTimeMillis(); String s1 = ""; for(int i = 0; i < 10000; ++i){ s1 += i; } long end = System.currentTimeMillis(); long time = end-start; System.out.println("普通方法拼接时间:"+ time); //用StingBuilder类拼接 start = System.currentTimeMillis(); StringBuilder s3 = new StringBuilder(); for(int i = 0; i < 10000; ++i){ s3.append(i); } end = System.currentTimeMillis(); time = end-start; System.out.println("StringBuilder 拼接时间:"+ time); }
结果如下:
我们用直接使用String类拼接的字符串的话,每拼接一次就会创建一个新的对象,次数一多运行时间就会变长。所以当我们频繁修改字符串的情况考虑使用StringBuilder类进行操作。
我再举一个LeetCode上实际操作的例题,如下:
StringBuilder类拼接 1ms
普通拼接 23ms
大家感兴趣了,可以去做一下这道题:根据二叉树创建爱字符串
Ⅲ了解StringBuilder类修改内部字符串过程
我们看下图
首先在栈中创建一个StringBuilder变量sb,然后在堆中开辟一块空间,被sb引用。
append方法我们可以看做把参数传给 StringBuilder对象
当sb第一次调用append方法时,编译器会先把“Hello”放到字符串常量池中,然后再把“Hello”传给sb引用对象。
当sb第二次调用append方法时,编译器同样会先把 " World" 放到字符串常量池中,但此刻 sb 并不会new一个新的对象来接受append方法传来的 " World",而是在原来的对象内部直接进行拼接。
我们观察 append方法 就会发现,append方法最后返回的是 "this"!也就是原来的对象。
这也就是为什么StringBuilde对象能修改字符串的原因。
2、介绍StringBuilder和StringBuffer及一些常用的方法
上面我们介绍了 StringBuilder,其实为了方便字符串的修改,Java中又提供StringBuffer类。
这两个类的大部分功能是相同的。如下
public static void main(String[] args) { StringBuffer sb = new StringBuffer(); sb.append("你好!"); sb.append("我是威威"); String str = sb.toString(); System.out.println(str); }
而除了append和toString之外,StringBuilder和StringBuffer中包含各种各样的方法。
这里介绍一些常用的,其它需要用到了大家可参阅 StringBuilder在线文档
以下以StringBuilder为例,StringBuffer中方法类似
方法 | 说明 |
StringBuff append(String str) |
在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、 double、float、int、long、Object、String、StringBuff的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) |
扩容 |
void setCharAt(int index, char ch) |
将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) |
从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str, int fromIndex) |
从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(int offset, String str) |
在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) |
删除index位置字符 |
StringBuffer delete(int start, int end) |
删除[start, end)区间内的字符 |
StringBuffer replace(int start, int end, String str) |
将[start, end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
String substring(int start,int end) |
将[start, end)范围内的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
3、StringBuilder和StringBuffer区别
为了对比StringBuilder和StringBuffer,我们来看一下他俩 append方法的具体代码
我们发现,StringBuffer的append方法中,多了一个 synchronized,而 synchronized 含义是保护线程安全。平时遇到多线程时,用StringBuffer的比较多。
所以StringBuilder和StringBuffer区别在于:
StringBuffer采用同步处理,属于线程安全操作;
StringBuilder未采用同步处理,属于线程不安全操作;
拓展:如何打开字节文件
我们在idea操作中,点击上面的小框
点击后,找到Openin后点击Explorer,这时会弹出一个文件夹。
点击 2022-7-12,找到out文件,进去点击production,再点击 2022-7-12,之后就能看见我们.class文件。
这里 2022-7-12 是我自己创建的文件名,而且我的 .class 文件在 demo2 包中,所以多跳了一步。
然后按着Shift键,右键点击 .class 文件,然后点击 “PowerShell”,就会弹出一个窗口
尽量点击文件中间空白部分,部分可能找不到 “PowerShell”,这个选项
接着我们在窗口中输入 javap -c 文件名,就能看到我们代码编译后字节码啦
到此,本节内容就讲完了,有错误的地方希望大家能批评指正,别忘了点赞👍+收藏⭐️哦
😜 关注我!带来等多精彩🎉🎉