String
String概念
String,字符串类,对多个字符的char[]类型进行封装,并实现了许多实用api接口
jdk9之后,Unicode的子集ASCII字符因为一个字节足以表示,所以此版本之后,ASCII字符会用字节数组byte[]存储,其他仍然使用char[]存储,以此优化String存储
String特点
- 变量值不可变
- 类不可被继承(被final修饰)
主要构造方法
String有很多构造方法
- String()
- String(String)
- String(byte[])
- String(char[])
- 字面量赋值法
字面量赋值,底层依靠常量池实现
当使用字面量创建字符串时,
JVM 首先会检查字符串常量池中是否已经存在相同内容的字符串。
如果已经存在,就直接返回该字符串在常量池中的引用;
如果不存在,则在常量池中创建一个新的字符串对象,并返回其引用
在文《java内存模型-static关键字》中,将常量池划分到方法区是不完全正确的
jdk7之前:常量池在方法区
jdk7及以后:常量池在堆内存
package tools;
public class TestString {
public static void main(String[] args) {
String s0 = new String();
// 字面量赋值
String s1 = "abc";
// 传入String类型
String s2 = new String(s1);
// 传入字节数组
byte[] bytes = {97,98,99};
String s3 = new String(bytes);
// 传入字符数组
char[] chars = {'a','b','c'};
String s4 = new String(chars);
System.out.println("输出s0:"+s0);
System.out.println("输出s1:"+s1);
System.out.println("输出s2:"+s2);
System.out.println("输出s3:"+s3);
System.out.println("输出s4:"+s4);
}
}
String值与内存
本质还是值与地址的问题
public class TestString {
public static void main(String[] args) {
String s0 = "abc";
String s1 = "abc";
String s2 = new String(s1);
System.out.println(s1 == s0); // true ,共享了常量池的"abc"
System.out.println(s2 == s1); // false,new之后,重新划分堆内存给s2,
System.out.println(s2.equals(s1)); // true 值与s1一样,此张伟非彼张伟(String类的equals比较内容)
String s3 = s1;
System.out.println(s3 == s1); // true,共享了常量池的“abc”,大名张伟,小名阿伟
s3 = s2;
System.out.println(s3 == s2); // s2、s3的引用同样指向s2指向的地址,大名张伟,小名阿伟
System.out.println(s1 + s2); // abcabc 使用+号简单字符串拼接
}
}
== 与 equals区别
==:逻辑远算符,比较基本类型的值或对象在堆的地址
equals:牢大Object类的一个方法,比较对象地址
String重写了此方法,判长、逐位比较
String类API接口
- int lenght():返回字符串长度
- char charAt(int index):返回index位置的字符,从0开始
- boolean equals(Object object):主要比较String类的内容
- boolean startsWith(String pref):判断是否以pref参数开头
- boolean endsWith(String suf):判断是否以suf参数结尾
- String substring(int begin):从指定的begin开始,截取到字符串末尾,返回一个新的字符串
- String substring(int begin, int end):从指定的begin开始,截取到字符串end位置(不包括end位置),返回一个新的字符串
- int indexof(int ch):返回ASCII数字sh对应的字符第一次出现的位置
- int indexof(char ch):返回字符ch第一次出现的位置
- int indexof(String s):返回字符串s第一次出现的位置
- String replace(char old, char new):把所有的old字符替换成new的字符
- String[] split(String regex):按照符合正则表达式的字符,分割字符串,得到字符串数组(不包括分割点)
- String trim():去除字符串两头的孔字符串,返回新的字符串
package tools;
import java.util.Arrays;
public class TestString {
public static void main(String[] args) {
String s1 = "HelloWorld !";
System.out.println(s1.length()); // 13
System.out.println(s1.charAt(1)); // e
System.out.println(s1.equals("abcdefg")); // false
System.out.println(s1.startsWith("He")); // true
System.out.println(s1.endsWith("old")); // false
System.out.println(s1.substring(2)); // 截取:从2位置开始 lloWorld !
System.out.println(s1.substring(2,5)); // 截取:从2到5,不包括5 llo
System.out.println(s1.indexOf(101)); // ASCII码101对应的字符出现的第一个位置 1
System.out.println(s1.indexOf('e')); // 字符'e'出现的第一个位置 1
System.out.println(s1.indexOf("oW")); // 字符串"oW"出现的第一个位置
System.out.println(s1.replace('!','~')); // 替换字符 HelloWorld ~
System.out.println(s1.replace(" !","~")); // 替换字符串 HelloWorld~
String s2 = " 12345 ";
System.out.println(s2);
System.out.println(s2.trim()); // 去除两端 "12345"
String s3 = "java-C++-Python-Go";
System.out.println(Arrays.toString(s3.split("-")));
// 以'-'为分割点,分割字符串得到数组{"java","C++","Python","Go"}
}
}
由上可知,当替换、截取等操作String对象,需要返回新的字符串,原来的String对象不改变
StringBuilder
可变字符串,需要关注
构造方法:StringBuilder(String s)
成员方法
- StringBuilder
append
(String str):尾部拼接str,返回本身 - StringBuilder
insert
(int index, String str):在index处插入字符串str(也可以传入char类型),返回本身 - StringBuilder
delete
(int start, int end):删除start位置到end(不包括end位置),返回本身 - StringBuilder
deleteCharAt
(int index):删去位置index的字符,返回本身 - String toString():转成String类型
public class TestStringBuilder {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("97");
System.out.println(sb);
System.out.println(sb.append("9899100"));
System.out.println(sb.insert(2,"101")); // 971019899100
System.out.println(sb.delete(2,5)); // 删去101 979899100
System.out.println(sb.deleteCharAt(5)); // 删去位置5的字符: 97989100
System.out.println(sb.toString()); // 返回String类型的字符串,但不影响sb变量
}
}
StringBuilder对象的操作都是返回自己,达到可变字符串的目的
StringBuffer
可变字符串
方法与StringBuilder相似,不同的是StringBuffer成员方法大多被synchronized
关键字修饰使线程同步,达到可变字符串且线程安全的目的,正因如此,StringBuilder效率更快(无需处理线程同步)
StringBuffer更安全
String–StringBuffer–StringBuilder三者的关系总结
String 字符串不可变
StringBuffer成员方法被synchronized
修饰,可变且线程安全
StringBuilder可变但线程不安全,但是因不需要处理线程同步,效率更快