目录
9.1、StringBuilder和StringBuffer
1、字符串构造
String类提供的构造方式非常多,常用的就以下三种
1.使用常量串构造
String str = "hello"; // "hello" 字符串常量 ,没有\0 标记结尾
System.out.println(str); // 输出hello^
2.直接new String对象
String str2 = new String(); // 调用String类不带参数的构造方法
System.out.println(str2); // 输出空白.
String str3 = new String("pppp"); // 调用String类带参数的构造方法
System.out.println(str3); // 输出pppp^
3.使用字符数组进行构造
char[] array ={'a','b','c'};
String str4 = new String(array);
System.out.println(str4); // 输出abc.
char[] array ={'a','b','c'};
String str4 = new String(array,1,2);
System.out.println(str4); // 输出ab
1.1、构造原理
String类的实现源码中,String类的成员变量如下

构造方法:

String s1 = new String("hello");
String s2 = new String("world");
String s3 = s1;
System.out.println(s1.length()); // 获取字符串长度---输出5
System.out.println(s1.isEmpty()); // 如果字符串长度为0,返回true,否则返回false
注意区分字符串长度为0和字符串为null的情况:
String str4 = ""; // 表示字符串长度为0
System.out.println(str4.length()); // 输出0
System.out.println(str4.isEmpty()); // 输出true^
String str5 = null; // 表示str5不指向任何对象//System.out.println(str5.length()); // 空指针异常
System.out.println(str5.isEmpty()); // 空指针异常
注:在Java中 "" 引起来的也是String类型对象
// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());
2、String对象的比较
2.1、==
==比较是否引用同一个对象,比较的是引用中的地址
// 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
String s1 = new String("abc");
String s2 = new String("abc");String s3 = s1
System.out.println(s1 == s2); // 输出falseSystem.out.println(s1 == s3); // 输出true
^
// 对于基本类型变量,==比较两个变量中存储的值是否相同
int a = 10;
int b = 20;
int c = 10;
System.out.println(a == b); // false
System.out.println(a == c); // true
2.2、equals方法
String类重写了父类Object中equals方法,Object中equals默认按照 == 比较,String重写equals方法后,比较内容。 返回值是boolean类型的
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("Hello");
// equals比较:对String对象逐个字符进行比较
// 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true
// s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出false System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // false
2.3、compareTo方法
String类实现了Comparable接口,重写了Comparable接口的compareTo方法
具体比较方式:
- 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
- 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
/**
* s1 和 s2 进行比较
* 如果s1 > s2 返回正数
* 如果s1 == s2 返回0
* 如果s1 < s2 返回负数* 不能忽略大小写
*/
System.out.println(s1.compareTo(s2)); // 不同,输出字符差值-1 System.out.println(s1.compareTo(s3)); // 相同,输出 0System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
compareToIgnoreCase方法,可以忽略大小写比较
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("ABc");
String s4 = new String("abcdef");
System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
3、字符串查找
String类提供的常用查找的方法:

1.char charAt(int index)
^
String s1 = "hello";
for (int i = 0; i < s1.length(); i++) {
char ch = s1.charAt(i);
System.out.print(ch + " "); // 输出 h e l l o
}
2.int indexOf(int ch)
^
String s1 = "hello";
// 从头到后 查某个字符 第一次出现的下标
int index = s1.indexOf('l');
System.out.println(index); // 输出2.
3.int indexOf(int ch, int fromIndex)
^
// 从fromIndex位置开始找ch第一次出现的位置
int index = s1.indexOf('l',3);
System.out.println(index); // 输出3.
4.int indexOf(String str)
^
// 返回子串在主串中第一次出现的位置下标
String s1 = "ababcabcd";
int index = s1.indexOf("abc");
System.out.println(index); // 输出2.
5.int indexOf(String str, int fromIndex)
^
// 从fromIndex位置开始找
String s1 = "ababcabcd";
int index = s1.indexOf("abc",3);
System.out.println(index); // 输出5
6.int lastIndexOf(int ch)
^
// 从后往前找,返回ch第一次出现的位置
String s1 = "ababcabcd";
int index = s1.lastIndexOf("abc");
System.out.println(index); // 输出5.
7.int lastIndexOf(int ch, int fromIndex)
^
//从fromIndex位置开始找
String s1 = "ababcabcd";
int index = s1.lastIndexOf("abc",4);
System.out.println(index); // 输出28.int lastIndexOf(String str)
//从后往前找,返回str第一次出现的位置
9.int lastIndexOf(String str, int fromIndex)
//从fromIndex位置开始找,从后往前找str第一次出现的位置
4、转化
4.1、数值和字符串转化
valueOf
// 数字转字符串
String s1 = String.valueOf(1234);
String s2 = String.valueOf(12.34);
String s3 = String.valueOf(true);
String s4 = String.valueOf(new Student("Hanmeimei", 18));
System.out.println(s1);
System.out.println(s2);System.out.println(s3);
System.out.println(s4);
parseInt
// 字符串转数字
// Integer、Double等是Java中的包装类型
int data1 = Integer.parseInt("1234");
double data2 = Double.parseDouble("12.34");
System.out.println(data1);
System.out.println(data2);
4.2、大小写转换
toUpperCase
String s1 = "hello";//转变为大写 不是在原来的基础上 转变 是转变成大写后是一个新的对象
String ret = s1.toUpperCase();System.out.println(s1); // hello
System.out.println(ret); // HELLO^
toLowerCase
String s2 = "HEllo";String ret2 = s2.toLowerCase();
System.out.println(s2); // HEllo
System.out.println(ret2); // hello
4.3、字符串转数组
toCharArray
String s1 = "hello";
char[] array = s1.toCharArray();
System.out.println(Arrays.toString(array)); // [h,e,l,l,o]^
// 数组转字符串
char[] array2 = {'a','b','c'};
String str2 = new String(array2);
System.out.println(str2); // abc
4.4、格式化
format
String s = String.format("%d-%d-%d", 2024, 12,19);
System.out.println(s); // 2024-12-19
4.5、去空格
trim
String str2 = " fdsafsafdsa fdsafsaf ";
System.out.println(str2);// 去掉字符串的左右两边的空格 中间的空格无法去掉
System.out.println(str2.trim());
5、字符串替代
replace
可以看到replace有一个参数是CharSequence的
String实现了CharSequence接口,所以replace方法可以传入String类型的参数
^
String str = "ababcabcdabcde";
String ret = str.replace("ab","00");System.out.println(ret); // 0000c00cd00cde
ret = str.replace('a','8');
System.out.println(ret); // 8b8bc8bcd8bcde

ret = str.replaceFirst("ab","123");
System.out.println(ret); // 123abcabcdabcde
ret = str.replaceAll("ab","123");
System.out.println(ret); // 123123c123cd123cde
6、字符串拆分
将一个完整的字符串按照指定的分隔符划分为若干个子字符串
1.String[] split(String regex) -> 将字符串全部拆分
^
String str = "hello abc world";
String[] ret = str.split(" "); // 以空格划分
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}2.String[] split(String regex, int limit) -> 将字符串以指定的格式,拆分为limit组
^
String str = "hello abc world";
String[] ret = str.split(" ",2); // 以空格划分,拆成两组
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}
注意:
1.字符 "|","*","+" 都得加上转义字符,前面加上 "\\"
String str = "192.168.1.1";
String[] ret = str.split("\\."); // \\ 表示 \,\. 表示 .
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}
2.如果是 "\\",那么就得写成 "\\\\"
String str = "192\\168\\1\\1";
String[] ret = str.split("\\\\"); // \\ 表示 \,\\\\表示\\
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}
3.如果一个字符串中有多个分隔符,可以用"|"作为连字符
String str = "name=zhangsan&age=15";
String[] ret = str.split("=|&");
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}^
//也可以在 第一次分割的基础上 进行第二次分割
String[] ret = str.split("&");
for (int i = 0; i < ret.length; i++) {
String x = ret[i];
String[] ret2 = x.split("=");
for (int j = 0; j < ret2.length; j++) {
System.out.println(ret2[j]);
}
}
7、字符串截取
1.String substring(int beginIndex) -> 从指定索引截取到结尾
String str = "ababc";
ret = str.substring(2);
System.out.println(ret); // abc
^
2.String substring(int beginIndex, int endIndex) -> 截取部分内容
String str = "ababc";
String ret = str.substring(0,3); // [0,3)System.out.println(ret); // aba
8、字符串的不可变性
所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
String类在设计时就是不可改变的,String类实现描述中已经说明了(JDK1.8)
String类中的字符实际保存在内部维护的value字符数组中
从图中可以看出
- String类被final修饰,表明该类不能被继承
- value被修饰被final修饰,表明value不能再引用其它字符数组,但是其引用空间中的内容可以修改
因此字符串不可变的原因与这两个 final 无关
决定字符串不可变的是value这个引用是私有的(private修饰),在其他类中无法拿到
9、字符串修改
应尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下
public static void main(String[] args) {
String s = "hello";
s += " world";
System.out.println(s); // 输出:hello world
}// 这种方式不推荐使用,看似简单的操作,其实中间创建了好多临时对象,效率低
这种写法与下述写法等价
public static void main(String[] args) {
String str = "hello";
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(str);
stringBuilder.append("abc");
str = stringBuilder.toString();
System.out.println(str);
}
// 可以看到过程中创建了StringBuilder对象和新的字符串对象
9.1、StringBuilder和StringBuffer
由于String的不可更改特性,为了方便字符串的修改,Java中提供StringBuilder和StringBuffer类。这两个类的方法都一样,下面列举了一些常用方法


StringBuffer / StringBuilder 类的 append() 方法有三种语法形式,分别如下:
1. append(任意类型的参数):将参数以字符串的形式追加到 StringBuffer 对象的末尾。
2. append(任意类型的参数, 始索引, 束索引):将参数在指定索引之间的字符追加到StringBuffer 对象的末尾。
3.append(char[] chars):将参数以字符串的形式追加到StringBuffer对象的末尾。
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = sb1;
// 追加:即尾插-->字符、字符串、整形数字
sb1.append(' '); // hello
sb1.append("world"); // hello world
sb1.append(123); // hello world123
System.out.println(sb1); // hello world123
System.out.println(sb1 == sb2); // true
System.out.println(sb1.charAt(0)); // 获取0号位上的字符 h
System.out.println(sb1.length()); // 获取字符串的有效长度14
System.out.println(sb1.capacity()); // 获取底层数组的总大小
sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123
sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123
System.out.println(sb1);
System.out.println(sb1.indexOf("Hello")); // 获取Hello第一次出现的位置
System.out.println(sb1.lastIndexOf("hello")); // 获取hello最后一次出现的位置
sb1.deleteCharAt(0); // 删除首字符
sb1.delete(0,5); // 删除[0, 5)范围内的字符
String str = sb1.substring(0, 5); // 截取[0, 5)区间中的字符以String的方式返回
System.out.println(str);
sb1.reverse(); // 字符串逆转
str = sb1.toString(); // 将StringBuffer以String的方式返回
System.out.println(str);
}
注:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则
- String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
- StringBuilder变为String: 调用toString()方法
9.2、字符串修改的效率
public static void main(String[] args) {
long start = System.currentTimeMillis();
String s = "";
for(int i = 0; i < 10000; ++i){
s += i;
}
long end = System.currentTimeMillis();
System.out.println("String: "+ (end - start));
// StringBuffer
start = System.currentTimeMillis();
StringBuffer sbf = new StringBuffer("");
for(int i = 0; i < 10000; ++i){
sbf.append(i);
}
end = System.currentTimeMillis();
System.out.println("StringBuffer: "+ (end - start));
// StringBuilder
start = System.currentTimeMillis();
StringBuilder sbd = new StringBuilder();
for(int i = 0; i < 10000; ++i){
sbd.append(i);
}
end = System.currentTimeMillis();
System.out.println("StringBuilder: "+ (end - start));
}
运行结果:
String: 280
StringBuffer: 2
StringBuilder: 1
StringBuilder和StringBuffer的区别:
StringBuffer的方法比StringBuilder多了synchronized(保证线程安全)
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
总结:
- 直接对String类型对象进行修改的效率最低,因为它在修改的过程中创建了很多对象
- StringBuilder比StringBuffer的效率更高,因为同一时刻只有一个线程可以执行StringBuffer的方法,比StringBuilder多了上锁和开锁的步骤,耗费的更多时间
String与StringBuffer、StringBuilder的区别:
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改
- String和StringBuffer、StringBuilder包含的方法不一样








1510

被折叠的 条评论
为什么被折叠?



