Java SE 讨论String类
前言
在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提 供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了String类,因此String类是非常重要的。
学习目标:
- 了解 String类的基本用法。
- 熟练掌握 String类的常见操作。
- 认识 StringBuffer 和 StringBuilder。
1.string类的常见使用方法
1.1 字符串构造
String类提供的构造方法有很多种,但我们常用以下三种:
public class Main_1 {public static void main(String[] args) {//使用常量串构造String s1 = "hello world";System.out.println(s1);//使用 new String对象String s2 = new String("hello world");System.out.println(s2);//使用字符数组构造char[] ch = {'h','e','l','l','o'};String s3 = new String(ch);System.out.println(s3);}
}//运行结果:
//hello world
//hello world
//hello
若对其他构造方法感兴趣,可参考Java在线文档: https://docs.oracle.com/javase/8/docs/api/index.html
注意:
String是引用类型,内部并不储存字符本身,而是储存一个对象的地址,由这个对象储存字符。我们可以进入到String类的实现源码中会发现有几个变量:
通常,字符储存在 Byte数组value中,具体的话,举个例子:
现在有三个String变量,s1,s2和s3
String s1 = "abc"; String s2 = "ab"; String s3 = s1;
那么会存在这样逻辑关系:
解释:首先,s1和s2引用的是不同的对象,s3引用的对象与s1相同,那么s1与s3指向相同的对象,s2指向与它们不同的对象,我们又说,是字符数组value来储存字符的,而数组也是一种引用类型,因此两个对象的value储存的是不同的地址,分别指向两个不同的数组,分别存放各自的字符串的字符。
1.2 String对象的比较方法
字符串的比较是常见的操作之一,Java为我们提供了4种方法:
1.通过 == 比较是否引用同一个对象
public class Main_2 {public static void main(String[] args) {String s1 = "abc";String s2 = "ab";String s3 = s1;System.out.println(s1 == s2);System.out.println(s1 == s3);System.out.println(s2 == s3);}
}//运行结果:
//false
//true
//false
2.通过 equals()方法:按照字典序比较
字典序指的是字符大小的顺序。
String类重写了父类Object中equals方法,使得它按照以下顺序进行比较:
1.先检测是否为同一对象比较,如果是则返回 true,否则进入下一步。
2.检测被比较对象(即作为参数传入的对象)是否为 String对象,如果是则进入下一步,否则返回false。
3.检测比较对象(即调用方法的对象)与被比较对象长度是否相同,是就继续比较,否则返回false。
4.按照字典序,从前往后逐个字符进行比较。
public class Main_2 {public static void main(String[] args) {String s1 = "abc";String s2 = "abc";String s3 = "Abc";System.out.println(s1.equals(s2));System.out.println(s1.equals(s3));System.out.println(s2.equals(s3));}
}//运行结果
//true
//false
//false
3.通过compareTo()方法:按照字典序进行比较
String类实现了Comparable 接口,重写了compareTo()方法,但与equals()方法不同的是,它返回的不是boolean类型,而是int类型。
比较方式:
1.先按照字典序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值。
2.如果前k个字符相等(k为两个字符长度的最小值),则返回两个字符串长度差值。
public class Main_2 {public static void main(String[] args) {String s1 = "abc";String s2 = "ab";String s3 = "Abc";System.out.println(s1.compareTo(s2));System.out.println(s1.compareTo(s3));System.out.println(s2.compareTo(s3));}
}//运行结果:
//1
//32
//32
注意:a与A在字典序中相差32。
4.通过 compareToIgnore()方法:与compareTo()方法方式相同,但是忽略大小写比较
public class Main_2 {public static void main(String[] args) {String s1 = "abc";String s2 = "ab";String s3 = "Abc";System.out.println(s1.compareToIgnoreCase(s2));System.out.println(s1.compareToIgnoreCase(s3));System.out.println(s2.compareToIgnoreCase(s3));}
}//运行结果
//1
//0
//-1
1.3 字符串查找
在进入这个内容及后续的内容之前,先要搞清楚一件事,就是字符串也是有下标的(但不能直接访问),因为字符储存在数组中,不仅如此还可以用length()方法获取它的长度。
注:String类的length()是方法,而数组的length是字段。
字符串查找也是字符串中非常常见的操作,以下是String类提供的常用查找方法:
大致可以分为三个模块,按指定下标找,从前往后找、从后往前找,其中从前往后找和 从后往前找实现了方法的重载,因此同一个方法具有多种不同的实现方式。
注:它们都是非静态方法。
1.4 转换
String类转换操作主要有4中,分别是:数值转字符串、大小写转换、字符串转数组和格式化。
1. 数值转字符串
数值 ——> 字符串,通过String类的valueOf()方法实现(它是静态方法)。
字符串 ——> 数值,通过转换结果的类型的包装类型的valueOf()方法(也是静态的)实现。
public class Main_3 {public static void main(String[] args) {//数值转字符串int x1 = 100;double x2 = 3.14;String s1 = String.valueOf(x1);String s2 = String.valueOf(x2);System.out.println(s1 + 1);System.out.println(s2 + 1);System.out.println("==========");//字符串转数值int x3 = Integer.valueOf(s1);double x4 = Double.valueOf(s2);System.out.println(x3 + 1);System.out.println(x4 + 1);}
}//运行结果:
//1001
//3.141
//==========
//101
//4.140000000000001
Integer、Double分别是int和double的包装类型。
2.大小写转换
小 ——> 大,通过toUpperCase()方法。
大 ——> 小,通过toLowerCase()方法。
public class Main_4 {public static void main(String[] args) {String s1 = "abcd";String s2 = "ABCD";String s3 = "a-A";System.out.println(s1.toUpperCase());System.out.println(s2.toLowerCase());System.out.println(s3.toUpperCase());System.out.println(s3.toLowerCase());}
}//运行结果
//ABCD
//abcd
//A-A
//a-a
注意:能转换的只有字母表的26个字母,其他字符保持不变。
3.字符串转数组(通常是字符数组)
字符串 ——> 数组,通过toCharArray()方法。
数组 ——> 字符串,直接通过String类的构造方法即可。
public class Main_5 {public static void main(String[] args) {//字符串转数组String s = "hello";char[] ch = s.toCharArray();System.out.println(ch);System.out.println("==========");//数组转字符串String s1 = new String(ch);System.out.println(s1);}
}//运行结果
//hello
//==========
//hello
4.格式化
格式化用于生成符合特定格式要求的字符串。它允许你将变量、对象或值插入到模板字符串中,并控制它们的显示方式(如数字精度、日期格式、对齐方式等),通过String类的 format()方法实现。
public class Main_6 {public static void main(String[] args) {String s = String.format("%d-%d-%d",2025,7,19);System.out.println(s);}
}//运行结果
//2025-7-19
%d 为占位符,与C语言中的类似,‘ - ’ 可以根据我们的需要换成别的字符。
1.5 字符串替换
一个重要的知识点:任何对字符串的修改都不在原字符串上进行修改,而是生成新字符串。(稍后解释)
字符串替换指的是:使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
举例:
public class Main_7 {public static void main(String[] args) {String s1 = "abababll";String s2 = s1.replace('a','c');String s3 = s1.replace("ab","ooo");String s4 = s1.replaceAll("ab","ooo");String s5 = s1.replaceFirst("ab","ooo");System.out.println(s1);System.out.println(s2);System.out.println(s3);System.out.println(s4);System.out.println(s5);}
}//运行结果
//abababll
//cbcbcbll
//oooooooooll
//oooooooooll
//oooababll
1.6 字符串拆分
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。可用方法如下:
举例:
public class Main {public static void main(String[] args) {String s = "name = xiaoming&age = 12";String[] strings = s.split("&");for (int i = 0; i < strings.length; i++) {System.out.println(strings[i]);}}
}//运行结果
//name = xiaoming
//age = 12
注意事项:
- 字符"|","*","+"都得加上转义字符,前面加上"\\"。
- 如果是"\",那么就得写成"\\\\"。
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符。多次拆分:
public class Main {public static void main(String[] args) {String s = "name = xiaoming&age = 12";String[] strings = s.split("&|=");for (int i = 0; i < strings.length; i++) {System.out.println(strings[i]);}} }//运行结果 //name // xiaoming //age // 12
1.7 字符串截取
从一个完整的字符串之中截取出部分内容。可用方法如下:
举例:
public class Main_8 {public static void main(String[] args) {String s = "aaaabbbbcccc";String s1 = s.substring(3);String s2 = s.substring(3,10);System.out.println(s);System.out.println(s1);System.out.println(s2);}
}//运行结果:
//aaaabbbbcccc
//abbbbcccc
//abbbbcc
1.8 其他操作方法
举例:
public class Main_9 {public static void main(String[] args) {String s = " hello,world ";System.out.println("[" + s + "]");System.out.println("[" + s.trim() + "]");}
}//运行结果:
//[ hello,world ]
//[hello,world]
2.字符串的不可变性
String对象是一种不可变对象,即字符串中的内容是不可改变的。究其原因是:我们知道String对象中存在一个数组value,它用于储存字符串的字符,但它被 private 修饰,意味着它无法被直接访问,也就是我们没法拿到它并对它进行操作。因此字符串中所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象。
也正因为String的不可变性,在对String对象进行修改时,不能直接原对象进行修改,要创建新对象再修改,因此效率十分低下。想要提高效率,就需要StringBuilder类 和 StringBuffer类了。
3. StringBuilder类 和 StringBuffer类
由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的,这里介绍 StringBuilder常用的一些方法,其它需要用到了大家可参阅:
https://docs.oracle.com/javase/8/docs/api/
举例:
public class Main {public static void main(String[] args) {StringBuilder s1 = new StringBuilder("hello");s1.append(" world"); //hello worlds1.append(123); //hello world123s1.reverse(); //将字符串s1翻转String str = s1.toString(); //将StringBuilder ——> StringSystem.out.println(str);}
}//运行结果
//321dlrow olleh
从这个例子可以看出来了,String 与 StringBuilder 最大的区别在于 String的内容无法修改,而StringBuilder的内容可以修改。 因此在频繁修改字符串的情况下,应该考虑使用StringBuilder。
注意!String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
- String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
- StringBuilder变为String: 调用toString()方法。
4.也许会出现的面试题
String、StringBuilder和StringBuffer的区别:
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。
- StringBuffer与StringBuilder大部分功能是相似的。
- StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。简单来说就是StringBuffer适用于多线程,StringBuilder用于单线程。
单线程与多线程的简单理解:
用厕所来举例,单线程好比自己家里的厕所,使用时不用刻意的去上锁,而多线程相当于是公共厕所,使用时需要上锁,也就是要采取安全措施,否则不安全。
到此,本篇文章也就结束了,多谢您的观看,如有错误,还请指出,谢谢!