前言
字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。
1.String类的方法
1.字符串的构造方法
使用常量串构造
String s1 = "hello world";
System.out.println(s1);
直接newString对象
String s2 = new String("hello world");
System.out.println(s2);
使用字符数组进行构造
char[] array = {'h','e','l','l','o',' ','w','o','r','l','d'};
String s3 = new String(array);
System.out.println(s3);
注意事项
- String是引用类型,内部并不存储字符串本身,String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上。
String s1 = "abcdef";
String s2 = "abcdef" + "xy";
String s3 = new String("xy");
- 在Java中“”引起来的也是String类型对象。
// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());
2.字符串的比较
1. ==比较是否引用同一个对象
public class TestDemo {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 10;
// 对于基本类型变量,==比较两个变量中存储的值是否相同
System.out.println(a == b);
System.out.println(a == c);
// 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("world");
String s4 = s1;
System.out.println(s1 == s2);
System.out.println(s2 == s3);
System.out.println(s1 == s4);
}
}
2. boolean equals(Object anObject) 方法
String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较
public boolean equals(Object anObject) {}
- 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
- 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
- this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
4.从前往后逐个字符进行比较
public class TestDemo {
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("Hello");
// s1、s2、s3引用的是三个不同对象,因此==比较结果全部为false
System.out.println(s1 == s2);
System.out.println(s1 == s3);
// equals比较:String对象中的逐个字符
// 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true
// s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出false
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
}
}
3. int compareTo(String s) 方法
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:
- 先按照大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
- 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
public class TestDemo {
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2));
System.out.println(s1.compareTo(s3));
System.out.println(s1.compareTo(s4));
}
}
4. int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较
public class TestDemo {
public static void main(String[] args) {
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));
System.out.println(s1.compareToIgnoreCase(s3));
System.out.println(s1.compareToIgnoreCase(s4));
}
}
3.字符串的查找
public class TestDemo {
public static void main(String[] args) {
String str1 = "abcabababccde";
char ch = str1.charAt(1); // 获得对应位置的字符
System.out.println(ch);
for (int i = 0; i < str1.length(); i++) {
System.out.print(str1.charAt(i) + " ");
}
System.out.println(str1.indexOf('c'));//获得()内字符第一次出现的位置
System.out.println(str1.indexOf('c',5));//从指定位置开始找()内字符相应的位置
//相当于从主串当中 查找子串 KMP算法
System.out.println(str1.indexOf("ab"));//获得()内字符串第一次出现的开始位置
System.out.println(str1.indexOf("ab",2));//从指定位置开始找()内字符串相应的开始位置*/
System.out.println(str1.lastIndexOf('a'));//获得()内字符最后一次出现的开始位置
System.out.println(str1.lastIndexOf('a',7));//获得fromIndex长度的字符串(abcababa),获得()内字符最后出现的位置(从后往前找)
System.out.println(str1.lastIndexOf("ab"));//获得()内字符串最后一次出现的开始位置
System.out.println(str1.lastIndexOf("ca",7));//获得fromIndex长度的字符串(abcababa),获得()内字符最后出现的位置(从后往前找)
}
}
4.字符串转换
1. 数值和字符串转化
class Person {}
public class TestDemo {
public static void main(String[] args) {
String str2 = String.valueOf(123);
System.out.println(str2);
String str3 = String.valueOf(new Person());
System.out.println(str3);
System.out.println("===========");
//基本类型对应的类类型 -> 基本类型也提供了面向对象的思想
String str4 = "123";
int data = Integer.parseInt(str4);//将字符串转换为数字
System.out.println(data);
}
}
2. 大小写转换
public class TestDemo {
public static void main(String[] args) {
String str1 = "abcde";
String str2 = "ABCD";
System.out.println(str1.toUpperCase());//小写转大写
System.out.println(str2.toLowerCase());//大写转小写
}
}
3. 字符串转数组
public class TestDemo {
public static void main(String[] args) {
String str1 = "abcdef";
char[] arr = str1.toCharArray();//字符串转数组
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
4. 格式化
public class TestDemo {
public static void main(String[] args) {
String s = String.format("%d-%d-%d",2023,1,3);
System.out.println(s);
}
}
5.字符串替换
public class TestDemo {
public static void main(String[] args) {
String str1 = "ababcabcde";
String ret1 = str1.replace('a','t');//将字符a替换为字符tt
System.out.println(ret1);
String ret2 = str1.replace("ab","tt");//将字符串ab替换为字符串tt
System.out.println(ret2);
String ret3 = str1.replaceAll("ab","66");//将字符串中所有ab替换为字符串66
System.out.println(ret3);
String ret4 = str1.replaceFirst("ab","tt");//将第一个字符串ab替换为字符串tt
System.out.println(ret4);
}
}
6.字符串拆分
public class TestDemo {
public static void main(String[] args) {
String str1 = "hello little boy";
String[] ret1 = str1.split(" ");//将字符串全部拆分
for (int i = 0; i < ret1.length; i++) {
System.out.println(ret1[i]);
}
System.out.println("=============");
String[] ret2 = str1.split(" ",2);//将字符串拆分成指定部分
for (int i = 0; i < ret2 .length; i++) {
System.out.println(ret2[i]);
}
}
}
public class TestDemo {
public static void main(String[] args) {
String str1 = "123&456=789";
String[] ret1 = str1.split("&|=");//用竖线来把分割条件整合在一起,分割多次
for (int i = 0; i < ret1.length; i++) {
System.out.println(ret1[i]);
}
String str2 = "123\\456\\789";
String[] ret2 = str2.split("\\\\");//需要进行转义
for (int i = 0; i < ret2.length; i++) {
System.out.println(ret2[i]);
}
String str3 = "123.456.789";
String[] ret3 = str3.split("\\.");//需要进行转义
for (int i = 0; i < ret3.length; i++) {
System.out.println(ret1[i]);
}
}
}
注意事项
- 字符"|“,”*“,”+"都得加上转义字符,前面加上 “\” .
- 而如果是 “” ,那么就得写成 “\\” .
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符.
7.字符串截取
public class TestDemo {
public static void main(String[] args) {
String str = "abcdefgh";
//从2位置开始截取所有的字符
String s1 = str.substring(2);
System.out.println(s1);
//从2位置开始截取到4的字符 [2,5)
String s2 = str.substring(2, 5);
System.out.println(s2);
}
}
注意事项:
- 索引从0开始。
- 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标。
8.其余操作方法
2.字符串的不可变性
字符串的不可变性是指字符串一旦被创建,就会在堆上生成这个字符串的实例,并且不可被改变,任何方法都不会改变字符串本身,而只会创建一个新的字符串。
String s = "abcd";
s = s.concat("ef");
如上的代码,在内存中,就会出现 2 个字符串对象。
String类在设计时就是不可改变的,String类实现描述中已经说明了。
String类中的字符实际保存在内部维护的value字符数组中。
- String类被final修饰,表明该类不能被继承。
- value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
3.字符串的修改
尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下,所以通常我们 借助StringBuffer 和 StringBuilder来修改
public class TestDemo {
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。
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
- String变为StringBuilder: 利用StringBuilder的构造方法或append()方法。
- StringBuilder变为String: 调用toString()方法。
4.String、StringBuffer、StringBuilder的区别
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。
- StringBuffer与StringBuilder大部分功能是相似的。
- StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。