目录
1. java.lang.StringBuffer类概述
-
StringBuffer是线程安全的可变字符序列.
-
线程安全 => 同步 => 效率低.
-
StringBuffer是一个类似String的字符串缓冲区.
-
多线程环境下用StringBuffer, 单线程环境下用StringBuilder.
-
对于线程安全的简单解释
- 线程安全 – 同步 – 效率低 – 我在做事时, 不允许别人做这件事.
- 线程不安全 – 不同步 – 效率高 – 我在做事时, 允许别人也做这件事.
- 线程的安不安全针对的是多线程环境, 单线程没有安不安全的说法.
- 若银行账号有1W元,甲乙分别通过银行卡和存折
同时刻
取1W元,
线程同步,只有一个人能取到1W;线程不同步,甲乙都能取到1W。
因此,多线程需要同步,安全;单线程用不同步,效率高。
2. StringBuffer和String的区别
3. StringBuffer的常用构造方法
public StringBuffer();
public StringBuffer(int capacity);
指定容量的字符串缓冲区对象。即要定义的这个字符串的最大长度。不写就默认16个字符.public StringBuffer(String str);
指定字符串内容的字符串缓冲区对象.
public static void main(String[] args) {
//----用无参构造创建对象(常用)----------------------------
StringBuffer sb1 = new StringBuffer();
System.out.println(sb1.toString());
System.out.println("容量:" + sb1.capacity());//16
System.out.println("长度:" + sb1.length());//0
//--用StringBuffer(int capacity)创建对象-------------
StringBuffer sb2 = new StringBuffer(50);
System.out.println(sb2.toString());
System.out.println("容量:" + sb2.capacity());//50
System.out.println("长度:" + sb2.length());//0
//--用StringBuffer(String str)创建对象---------------
StringBuffer sb3 = new StringBuffer("hello");
System.out.println(sb3.toString());
System.out.println("容量:" + sb3.capacity());//21=16+5
System.out.println("长度:" + sb3.length());//5
}
4. StringBuffer的常用成员方法
4.1 添加功能
public StringBuffer append(xxx);
在字符串末尾把任意类型数据添加到字符串缓冲区,并返回字符串缓冲区对象本身。public StringBuffer inset(int offset,xxx);
在指定位置把任意类型数据插入到字符串缓冲区,并返回字符串缓冲区对象本身。(注意插入并不是覆盖)
public static void main(String[] args) {
//创建字符串缓冲区对象
/*①*/
StringBuffer sb1 = new StringBuffer();
//调用添加数据的方法
/*②*/
StringBuffer sb2 = sb1.append("hello");
System.out.println(sb1);//hello
System.out.println(sb2);//hello
System.out.println(sb1 == sb2);//true
}
/*
* ①创建一个字符串缓冲区对象sb1(创建一个杯子sb1).
* ②调用方法在缓冲区添加字符串hello(往杯子里倒水),
* 这个方法返回放了字符串的对象sb1(返回装了水的杯子),并赋给了sb2
*
* 因此sb1、sb2都指向同一个字符串缓冲区
*/
//改进版:
public static void main(String[] args) {
//创建字符串缓冲区对象
StringBuffer sb1 = new StringBuffer();
//链式编程调用添加数据的方法
sb1.append("hello").append(123).append('a');
System.out.println(sb1);//hello123a
}
public static void main(String[] args) {
//创建字符串缓冲区对象
StringBuffer sb1 = new StringBuffer("helloworld");
//调用插入数据的方法
sb1.insert(5, "java");
System.out.println(sb1); // hellojavaworld
}
4.2 删除功能
public StringBuffer deleteCharAt(int index);
删除指定位置的字符,并返回删除后的字符串缓冲区对象本身public StringBuffer delete(int start,int end);
删除从指定位置开始指定位置结束的内容,并返回删除后的字符串缓冲区对象本身。(包左不包右。在java中几乎所有的从指定位置修改数据的方法都是包左不包右)
public static void main(String[] args) {
//创建对象
StringBuffer sb = new StringBuffer("helloworld");
//调用方法1
sb.deleteCharAt(3);
System.out.println(sb);//heloworld
//调用方法2
sb.delete(5, 8);
System.out.println(sb);//helowd
}
//删除所有的数据
public static void main(String[] args) {
//创建对象
StringBuffer sb = new StringBuffer("helloworld");
//调用方法1
sb.delete(0, sb.length());
System.out.println(sb);//空
}
//字符串缓冲区对象中的内容清空了,可以添加新的内容。
//杯子中水倒光了,可以重新盛水。
4.3 替换功能
public StringBuffer replace(int start,int end,String str);
把从start开始到end结束的字符串,替换成str。(包左不包右)
public static void main(String[] args) {
//创建对象
StringBuffer sb = new StringBuffer("helloworld");
//调用方法
sb.replace(0, 5, "过年好");
System.out.println(sb);//过年好world
}
4.4 翻转功能
public StringBuffer reverse();
public static void main(String[] args) {
//创建字符串缓冲区对象
StringBuffer sb = new StringBuffer("ABCDE");
//调用方法
sb.reverse();
System.out.println(sb);//EDCBA
}
4.5 截取功能
public String substring(int start);
删除从下标start开始的所有字符串.public String substring(int start,int end);
删除从start开始,到end结束的所有字符串。(包左不包右)
public static void main(String[] args) {
//创建字符串缓冲区对象
StringBuffer sb = new StringBuffer("ABCDE");
//调用截取方法
String s = sb.substring(2);
System.out.println(sb);//ABCDE
System.out.println(s);//CDE
}
//注意返回值类型是String不是StringBuffer
public static void main(String[] args) {
//创建字符串缓冲区对象
StringBuffer sb = new StringBuffer("66HELLO66");
//调用截取方法
String s = sb.substring(2, 7);
System.out.println(sb);//ABCDEFGH
System.out.println(s);//HELLO
}
4.6 其他功能
public int capacity();
返回当前容量。理论值。(杯子的最大容积)若不在构造中声明该字符串缓冲区的容量,默认个16字符。public int length();
返回长度(字符数)。实际值。(杯子的实际盛水量)
5. 注意
-
StringBuffer的toString方法默认重写了
-
不能把字符串的值直接赋给StringBuffer: StringBuffer="hello"; × -------------------------------------- String s="hello"; StringButter sb=s; ×
6. java.lang.StringBuilder类概述
- 线程不安全,不同步、但是效率高的可变字符串。
因为不同步,只能用于单线程使用。
StringBuffer的所有功能她都有。
此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。 - 安不安全指的是多线程情况下;单线程没有安不安全的说法。
因此多线程用StringBuffer,安全,但是效率慢;
单线程用StringBuilder,效率高。
7. 关于StringBuffer的题目
##7.1 String和StringBuffer的相互转换(字符串和字符串缓冲区的转换)
-
为什么进行类之间的转换
- 我们将A类转换为B类,是为了使用B类的方法,我们可能要的结果是A类型,所以还得转回来。
向下转型也是这个目的.
- 我们将A类转换为B类,是为了使用B类的方法,我们可能要的结果是A类型,所以还得转回来。
-
我们常用的是String,为了用StringBuffer中的方法,我们需要把String转成StringBuffer,用完方法我们想得到的是String,我们需要把StringBuffer转成String.
-
String→StringBuffer
-
法一:通过StringBuffer的构造函数
public static void main(String[] args) { String s = "hello"; StringBuffer sb = new StringBuffer(s); }
-
法二:通过append方法
public static void main(String[] args) { String s = "hello"; StringBuffer sb = new StringBuffer(); sb.append(s); }
-
-
StringBuffer→String
-
法一:通过String的构造方法
public static void main(String[] args) { StringBuffer sb = new StringBuffer("hello"); String s = new String(sb); }
-
方式二:通过toString方法
/* * StringBuffer的toString方法默认重写了,返回String类型的StringBuffer中的内容 */ public static void main(String[] args) { StringBuffer sb = new StringBuffer("hello"); String s = sb.toString(); }
-
7.2 把数组拼接成各种指定格式的字符串
-
法一:用字String做拼接
// 该方法能实现功能,但是浪费内存,不使用 public static String arrayToString(int[] arr) { String s = ""; s += "["; for (int x = 0; x < arr.length; x++) { if (x == arr.length - 1) s += arr[x]; else { s += arr[x]; s += ", "; } } s += "]"; return s; }
-
法二:用StringBuffer做拼接
// 此方法只开辟一块内存空间,效率高 public static String arrayToString(int[] arr) { StringBuffer sb = new StringBuffer(); sb.append("["); for (int x = 0; x < arr.length; x++) { if (x == arr.length - 1) sb.append(arr[x]); else sb.append(arr[x]).append(", "); } sb.append("]"); return sb.toString(); }
7.3 把字符串翻转
-
法一:用String做翻转拼接
// 倒序遍历即可 public static String method(String s) { String result = ""; char[] chs = s.toCharArray(); for (int x = chs.length - 1; x >= 0; x--) { result += chs[x]; } return result; }
-
法二:用StringBuffer的reverse();方法
//普通版 public static String method(String s) { StringBuffer sb = new StringBuffer(s); sb.reverse(); return sb.toString(); } //改进版 public static String method(String s) { return new StringBuffer(s).reverse().toString(); }
7.4 判断一个字符串是否是对称字符串
-
法一:挨个比较
/* * 分析: * 第一个和最后一个比较; * 第二个和倒数第二个比较; * ... * 比较的次数是长度除以2 */ //普通版 public static boolean method1(String s) { //先把字符串转成字符数组 char[] chs = s.toCharArray(); for (int start = 0, end = chs.length - 1; start <= end; start++, end--) { if (chs[start] != chs[end]) { return false; } } return true; } //改进版 public static boolean method2(String s) { boolean flag = true; //先把字符串转成字符数组 char[] chs = s.toCharArray(); for (int start = 0, end = chs.length - 1; start <= end; start++, end--) { if (chs[start] != chs[end]) { flag = false; break; } } return flag; }
-
法二:用字符串缓冲区的翻转功能
public static boolean method(String s) { return new StringBuffer(s).reverse().toString().equals(s); }
7.5 String StringBuffer StringBuilder 的区别
- 思路:
-
- 总
- String与StringBuffer/StringBuilder的区别
- StringBuilder与StringBuffer的区别
- 原理.
-
- 回答
- 字符串就是多个字符的集合, Java中有两种字符串, 一种是不可变字符串String, 另一种是可变字符串StringBuilder/StringBuffer
- String是一个常量, 是不可变的, 所以对于每次进行拼接和赋值操作, 都会创建一个新的String对象;
StringBuffer和StringBuilder都是可变的, 当进行字符串拼接的时候使用append方法, 操作的是同一个对象, 因此在拼接字符串方面, StringBuilder/StringBuffer的性能高于String. - StringBuilder是线程不安全的, StringBuffer是线程安全的, 因此StringBuilder的效率高于StringBuffer.
- 原理
- String类是final修饰的, String类的底层是char[ ] 也是被final修饰的. 因此使用String进行字符串的截取或拼接时, 都会生成一个新的对象, 因此效率低下.
- StringBuilder底层是可变长度的char[ ] , 初始化数组容量为16, 可以扩容, 其append()方法拼接字符串时内部调用System的native方法, 进行数组的拷贝, 不会重新生成新的StringBuilder对象.
7.6 String和StringBuffer分别作为参数传递
-
实际上这个问题问的是java到底是值传递还是引用传递.
-
java中只有值传递, 基本数据类型传递的是栈内存中的值, 引用数据类型传递的是引用变量中存储的对象的地址值. 引用变量不能被改变, 即引用变量中存储的对象的地址值不能被改变, 即引用变量不能指向另一个新的对象, 但是引用变量指向的对象的内容可以被改变.
package cn.king.demo01;
public class Demo09 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
// hello--------------world
System.out.println(s1 + "--------------" + s2);
change(s1, s2);
// hello--------------world
System.out.println(s1 + "--------------" + s2);
System.out.println("--------------------------");
StringBuffer sb1 = new StringBuffer("hello");
StringBuffer sb2 = new StringBuffer("world");
// hello--------------world
System.out.println(sb1 + "--------------" + sb2);
change(sb1, sb2);
// hello--------------worldworld
System.out.println(sb1 + "--------------" + sb2);
}
private static void change(StringBuffer sb1, StringBuffer sb2) {
sb1 = sb2;//s2的引用赋给了s1
sb2.append(sb1);//调用方法在s2后面添加hello
}
private static void change(String s1, String s2) {
s1 = s2;//s2的引用赋给了s1
s2 = s1 + s2;//先开辟空间盛放s1+s2的和,再让s2的引用指向这个空间
}
/*
* java中只有值传递, 形参的改变不会影响实参.
* 在change(String s1, String s2)中, 我们传进去的是
* s1. 我们并没有改变s1这个引用, 而是改变了这个引用指向的对象的内容.
* 也就是说, 我们不能将s1指向一个新的对象, 即s1不会被改变, s1中存储的对象的地址值不会改变.
* 但是我们能改变s1指向的对象的内容.
*/
}
7.7 将字符串中的字符进行排序
package cn.king.demo01;
/*
* 把字符串中的字符进行排序。
* 举例:"dacgebf"
* 结果:"abcdefg"
*
* 分析:
* A:定义一个字符串
* B:把字符串转换为字符数组
* C:把字符数组进行排序
* D:把排序后的字符数组转成字符串
* E:输出最后的字符串
*/
public class Demo09 {
public static void main(String[] args) {
// 定义一个字符串
String s = "dacgebf";
// 把字符串转换为字符数组
char[] chs = s.toCharArray();
// 把字符数组进行排序
bubbleSort(chs);
//把排序后的字符数组转成字符串
String result = String.valueOf(chs);
//输出最后的字符串
System.out.println("result:" + result);
}
// 冒泡排序
private static void bubbleSort(char[] chs) {
for (int x = 0; x < chs.length - 1; x++) {
for (int y = 0; y < chs.length - 1 - x; y++) {
if (chs[y] > chs[y + 1]) {
char temp = chs[y];
chs[y] = chs[y + 1];
chs[y + 1] = temp;
}
}
}
}
}