字符串相关的类
String类
- java.lang.String
- String类代表字符串,使用一对""引起来表示;
- Java程序中的所有字符串字面值都作为此类的实例实现;
- String内部定义了final char[] value用于存储字符串数据;
- 字符串是常量,一旦被赋值,就不能改变;
- String类是final类,不可被继承;
- String实现了Serializable接口:表示字符串是支持序列化的;
- String 实现了Comparable接口:表示String可以比较大小;
String类的不可变性
体现在执行以下操作时,需要重写指定内存区域赋值,不能使用原有的value进行赋值
- ① 当对字符串重新赋值时
- ② 当对现有的字符串进行连接操作时
- ③ 当调用String的replace()方法修改指定字符或字符串时
String对象创建的内存图
字符串内容为空和字符串对象为空的区别
String s1 = "";
String s2 = null;
System.out.println("isEmpty:" + s1.isEmpty());
//报错 NullPointerException
//s2对象不存在,不能调用方法,空指针异常
System.out.println("isEmpty:" + s2.isEmpty());
String类实例化方式的区别
- 通过字面量定义的方式:创建了一个对象
- 通过new + 构造器的方式:创建了两个对象
字符串常量池中有一个对象,堆中有一个字符串对象;
//此时的s1和s2的数据"hello"声明在方法区中的字符串常量池中
String s1 = "hello"; //创建了一个对象
String s2 = "hello";
//此时的s3和s4保存的是数据在堆空间中开辟空间以后对应的地址值
String s3 = new String("hello"); //创建了两个对象
//一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"hello"
String s4 = new String("hello");
//==:对于基本类型,比较的是值是否相同;
// 对于引用类型,比较的是地址值是否相同;
System.out.println(s1 == s2); //true
System.out.println(s1 == s3); //false
System.out.println(s1 == s4); //false
System.out.println(s3 == s4); //false
//equals:只能比较引用类型,默认也是比较地址值是否相同;
//而String类重写了equals()方法,比较的是内容是否相同;
System.out.println(s1.equals(s3)); //true
Person p1 = new Person("Tom",12);
Person p2 = new Person("Tom",12);
System.out.println(p1.name == p2.name); //true
字符串的拼接问题
常量与常量的拼接结果在常量池,且常量池中不会存在相同内容的常量;
只要其中有一个是变量,拼接结果就在堆中;
如果拼接的结果调用intern()方法,返回值就在常量池中;
//在字符串常量池中创建了一个字面量为"hello"的字符串
String s1 = "hello";
//在字符串常量池中创建了一个字面量为"world"的字符串
String s2 = "world";
//在字符串常量池中创建了一个字面量为"helloworld"的字符串
String s3 = "helloworld";
//s4指向字符串常量池中已经存在的"helloworld"字符串
String s4 = "hello" + "world";
//在堆空间中创建了一个新的字符串"helloworld"
String s5 = s1 + "world";
//在堆空间中创建了一个新的字符串"helloworld"
String s6 = "hello" + s2;
//在堆空间中创建了一个新的字符串"helloworld"
String s7 = s1 + s2;
//将字符串常量池中已经存在的"helloworld"字符串返回给s8
String s8 = s7.intern();
System.out.println(s3 == s4); //true
System.out.println(s3 == s5); //false
System.out.println(s3 == s6); //false
System.out.println(s3 == s7); //false
System.out.println(s5 == s6); //false
System.out.println(s5 == s7); //false
System.out.println(s6 == s7); //false
System.out.println(s3 == s8); //true
String类的常用方法
(1)判断:
boolean equals(Object obj):比较字符串的内容是否相同,区分大小写;
boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写;
boolean contains(String str):判断大字符串中是否包含小字符串;
boolean startsWith(String str):判断字符串是否以某个指定的字符串开头;
boolean endsWith(String str):判断字符串是否以某个指定的字符串结尾;
boolean isEmpty():判断字符串是否为空;
(2)获取:
int length():获取字符串的长度;
char charAt(int index):获取指定索引位置的字符;
int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引;
int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引;
int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引;
int indexOf(String str,int fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引;
(3)转换:String类的valueOf方法可以把任意类型的数据转成字符串;
static String valueOf(char[] chs):把字符数组转成字符串;
static String valueOf(int i):把int类型的数据转成字符串;
byte[] getBytes():把字符串转换为字节数组;
char[] toCharArray():把字符串转换为字符数组;
String toLowerCase():把字符串转成小写;
String toUpperCase():把字符串转成大写;
String concat(String str):把字符串拼接;
(4)截取:
String substring(int start):从指定位置开始截取字符串,默认到末尾;
String substring(int start,int end):从指定位置开始到指定位置结束截取字符串;
(5)替换:
String replace(char old,char new)
String replace(String old,String new)
(6)去除字符串两空格:
String trim()
(7)按字典顺序比较两个字符串:
int compareTo(String str)
int compareToIgnoreCase(String str)
StringBuffer类 / StringBuilder类
- java.lang.StringBuffer / java.lang.StringBuilder
- 均代表可变的字符序列,而且提供相关功能的方法也一样;
- 很多方法与String相同,可以对字符串内容进行增删,此时不会产生新的对象;
- 作为参数传递时,方法内部可以改变值;
- value没有final声明,value可以不断扩容;
StringBuffer的构造方法
StringBuffer类不同于String,其对象必须使用构造器生成;
- StringBuffer():无参构造方法,初始容量为16的字符串缓冲区
- StringBuffer(int size):构造指定容量的字符串缓冲区对象
- StringBuffer(String str):指定字符串内容的字符串缓冲区对象
源码分析:
//char[] value = new char[0];
String str = new String();
//char[] value = new char[]{'a','b','c'};
String str1 = new String("abc");
//char[] value = new char[16];
StringBuffer sb1 = new StringBuffer();
System.out.println(sb1.length())
sb1.append('a'); //value[0] = 'a';
sb1.append('b'); //value[1] = 'b';
//char[] value = new char["abc".length() + 16];
StringBuffer sb2 = new StringBuffer("abc");
System.out.println(sb2.length()); //3
扩容问题:
如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组;
默认情况下,扩容为原来容量的2倍 + 2,同时将原有数组中的元素复制到新的数组中;
开发中推荐使用:StringBuffer(int capacity) 或 StringBuilder(int capacity);
StringBuffer类的常用方法
(1)添加 append(xxx)
StringBuffer append(String str):可以把任意类型数据添加到字符串缓冲区里面;
(2)插入 insert(int offset, xxx)
StringBuffer insert(int offset,String str):在指定位置把任意类型的数据插入到字符串缓冲区里面;
(3)删除 delete(int start,int end)
StringBuffer deleteCharAt(int index):删除指定位置的字符;
StringBuffer delete(int start,int end):删除从指定位置开始指定位置结束的内容;
(4)替换
StringBuffer setCharAt(int n,char ch):替换指定位置的字符;
StringBuffer replace(int start,int end,String str):从start开始到end用str替换;
(5)查找
char charAt(int index):获取指定索引位置的字符;
(6)遍历
for() + charAt() / toString()
(6)反转
StringBuffer reverse()
(7)截取:返回值类型是String类型,本身没有发生改变;
String substring(int start):从指定位置开始截取字符串,默认到末尾;
String substring(int start,int end):从指定位置开始到指定位置结束截取字符串;
(8)其他
public int length():返回长度(字符数),实际值;
public int capacity():返回当前容量,理论值;
String 和 StringBuffer 的相互转换
String 转换为 StringBuffer :
// String -- StringBuffer
String str = "hello";
// 方式1:通过构造方法
StringBuffer sb = new StringBuffer(str);
System.out.println("sb:" + sb);
// 方式2:通过append()方法
StringBuffer sb2 = new StringBuffer();
sb2.append(str);
System.out.println("sb2:" + sb2);
StringBuffer 转换为 String :
// StringBuffer -- String
StringBuffer sb = new StringBuffer("world");
// 方式1:通过构造方法
String str = new String(sb);
System.out.println("str:" + str);
// 方式2:通过toString()方法
String str2 = sb.toString();
System.out.println("str2:" + str2);
把数组拼接成一个字符串
public static void main(String[] args) {
// 定义一个数组
int[] arr = {11, 22, 33, 44, 55};
// 方式1:用String做拼接的方式
String s1 = arrayToString(arr);
System.out.println("s1:" + s1);
// 方式2:用StringBuffer做拼接的方式
String s2 = arrayToString2(arr);
System.out.println("s2:" + s2);
}
方式1:用String做拼接的方式:
// 用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;
}
方式2:用StringBuffer做拼接的方式:
// 用StringBuffer做拼接的方式
public static String arrayToString2(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();
}
面试题:StringBuffer 和 String 的区别
- StringBuffer长度和内容可变,String不可变;
- 如果使用StringBuffer做字符串的拼接,不会浪费太多的资源;
面试题:StringBuffer 和 数组 的区别
- 二者都可以看出是一个容器,装其他的数据;
- 但是StringBuffer的数据最终是一个字符串数据;
- 而数组可以放置多种数据,但必须是同一种数据类型的;
面试题:String、StringBuffer、StringBuilder 的区别
三者底层都使用char[]存储;
三者的效率从高到低排列:StringBuilder > StringBuffer > String;
- String(JDK1.0):不可变字符序列;
- StringBuffer(JDK1.0):可变字符序列,同步的,效率低,线程安全;
- StringBuilder(JDK 5.0):可变字符序列,不同步的,效率高,线程不安全;
注意:作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder会改变其值;
字符串的常见案例
(1)模拟用户登录
(2)字符串的遍历
(3)统计字符串中大写,小写及数字字符的个数
(4)把字符串的首字母转成大写,其他小写
(5)统计大串中小串出现的次数
(6)把int数组拼接成一个指定格式的字符串
(7)字符串的拼接
(8)字符串的反转
(9)判断一个字符串是否对称