常用类1
常用类1
9.1字符串相关的类:String
String的特性
- String类:代表字符串。Java程序中的所有字符串字面值(如"abc")都作为此类的实例实现。
- String是一个final类,代表不可变的字符序列。
- 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
- String对象的字符内容是存储在一个霁符数组value[]中的。
package com.xin.cylei;
/*
String类的使用
*/
public class Day83000 {
public static void main(String[] args) {
Day83000 day = new Day83000();
day.test1();
}
/*
String:字符串,使用一对”"”引起来表示。
1.String声明为final的,不可被继承
2.String实现了serializable接口:表示字符串是支持序列化的。
实现了Comparable接口:表示String可以比较大小
3.String内部定义了final char[] value用于存储字符串数据
4.String:代表不可变的字符序列。简称:不可变性。
体现:1. 当对字符串变量重新赋值时,需要重新指定一个字符串常量的位置进行赋值,不能在原有的位置修改
当对现有的字符串进行拼接操作时,需要重新开辟空间保存拼接以后的字符串,不能在原有的位置修改
当调用字符串的replace()替换现有的某个字符时,需要重新开辟空间保存修改以后的字符串,不能在原有的位置修改
5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
6.字符串常量池中是不会存储相同内容的字符串的。
*/
public void test1(){
String s1="abc";//字面量的定义方式
String s2="abc";
System.out.println(s1==s2);//true,比较的是s1,s2的地址值
s1="123";
System.out.println(s1==s2);//false
System.out.println(s1);//123
System.out.println(s2);//abc
System.out.println("------------");
String s3="abc";
s3+="def";
System.out.println(s3);//abcdef
System.out.println("------------");
String s4="abc";
String s5=s4.replace('a','m');
System.out.println(s4);//abc
System.out.println(s5);//mbc
}
}
- final:String是不可被继承的
- Serializable:可序列化的接口。凡是实现此接口的类的对象就可以通过网络或本地流进行数据的传输。
- Comparable:凡是实现此接口的类,其对象都可以比较大小。
1.2内部声明的属性:
private final char value[]; //存储字符串数据的容器
2.字符串常量的存储位置
- 字符串常量都存储在字符串常量池(StringTable)中
- 字符串常量池不允许存放两个相同的字符串常量。
- 字符串常量池,在不同的jdk版本中,存放位置不同。
- jdk7之前:字符串常量池存放在方法区
jdk7及之后:字符串常量池存放在堆空间。
-
String实例化的两种方式
第1种方式:String s1 = "hello" ;
第2种方式:String s2 = new String( "hello");
package com.xin.cylei;
public class Day83001 {
public static void main(String[] args) {
String s1="abc";
String s2="abc";
String s3=new String("abc");
String s4=new String("abc");
System.out.println(s1==s2);//true
System.out.println(s1==s3);//false
System.out.println(s3==s4);//false
System.out.println(s1.equals(s3));//true
}
}
【面试题】
String s2 = new String("hello");在内存中创建了几个对象?两个!一个是堆空间中new的对象。另一个是在字符串常量池中生成的字面量。
- String的连接操作:+
- 情况1:常量+常量:结果仍然存储在字符串常量池中。注:此时的常量可能是字面量,也可能是final修饰的常量
- 情况2常量+变量或变量+变量﹔都会通过new的方式创建一个新的字符串,返回堆空间中此字符串对象的地址
- 情况3:调用字符串的intern():返回的是字符串常量池中字面量的地址
package com.xin.cylei.demo01;
public class Day83002 {
public static void main(String[] args) {
final String s1="hello";
String s2="world";
String s3="helloworld";
String s4="hello"+"world";
String s5=s1+"world";//通过查看字节码文件发现调用了StringBuilder的toString()---> new String()
String s6="hello"+s2;
String s7=s1+s2;
System.out.println(s3==s4);//true
System.out.println(s3==s5);//false,s1加final String s1="hello";变成true
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("========");
String s8=s5.intern();//intern():返回的是字符串常量池中字面量的地址
System.out.println(s3==s8);//true
}
}
(了解)情况4: concat(xxx):不管是常量调用此方法,还是变量调用,同样不管参数是常量还是变量,总之,调用完concat()方法都返回一个新new的对象。
package com.xin.cylei.demo01;
public class Day83003 {
public static void main(String[] args) {
String s1="hello";
String s2="world";
String s3=s1.concat(s2);
String s4="hello".concat("world");
String s5=s1.concat("world");
System.out.println(s3==s4);//false
System.out.println(s3==s5);//false
System.out.println(s4==s5);//false
}
}
String与常见的其它结构之间的转换
- String与基本数据类型、包装类之间的转换(复习)
- String 与char[]之间的转换
- String 与byte[]之间的转换(难度)
在utf-8字符集中,一个汉字占用3个字节,一个字母占用1个字节。
在gbk字符集中,一个汉字占用2个字节,一个字母占用1个字节。
utf-8或gbk都向下兼容了ascii码。
编码与解码:
编码:String --->字节或字节数组
解码:字节或字节数组----> String
要求:解码时使用的字符集必须与编码时使用的字符集一致!不一致,就会乱码。
package com.xin.cylei.demo01;
import java.io.UnsupportedEncodingException;
public class Day83004 {
public static void main(String[] args) throws UnsupportedEncodingException {
//在utf-8字符集中,一个汉字占用3个字节,一个字母占用1个字节。
String str=new String("hello中国");
// String -->byte[]:调用String的getBytes()
byte[] arr=str.getBytes();//使用默认的字符集utf-8
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("======");
//getBytes (String charsetName):使用指定的字符集
byte[] arr1=str.getBytes("gbk");
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
//byte--->String
String str1=new String(arr);//使用默认的字符集utf-8
System.out.println(str1);
String str2=new String(arr1,"gbk");//使用gbk
System.out.println(str2);
}
}
(1 ) boolean isEmpty():字符串是否为空
(2) int length():返回字符串的长度
(3 ) String concat(xx):拼接
(4) boolean equals(0bject obj):比较字符串是否相等,区分大小写
(5) boolean equalsIgnoreCase(object obj):比较字符串是否相等,不区分大小写
(6)int compareTo(String other):比较字符串大小,区分大小写,按照Unicode编码值比较大小
String s5="abc";
String s6="aBc";
System.out.println(s5.compareTo(s6));//32
(7)int compareToIgnoreCase(String other):比较字符串大小,不区分大小写
(8 ) String toLowercase():将字符串中大写字母转为小写
(9 ) String toUpperCase():将字符串中小写字母转为大写
(10)String trim():去掉字符串前后空白符
(11) public String intern():结果在常量池中共享
1.4.2系列2:查找
(11) boolean contains(xx):是否包含xx
(12) int indexof(xox):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1
(13) int indexOf(String str, int fromIndex):这凹指正丁才付中仕此于1中T弟人观ALS,开始
(14) int lastlndexOf(x):从后往前找当前字符串中x,即如果有返回最后一次出现的下标,要是没有返回-1
(15) int lastlndexof(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
1.4.3系列3:字符串截取
(16)String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
(17) String substring(int beginIndex, int endindex):返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
String ss="教育科比会更好";
System.out.println(ss.substring(2));//科比会更好
System.out.println(ss.substring(2,4));//科比,左闭右开【2,4)
1.4.4系列4:和字符/字符数组相关
(18) char charAt(index):返回[index]位置的字符
(19) char[] toCharArray():将此字符串转换为一个新的字符数组返回
(20) static String valueof(char[] data):返回指定数组中表示该字符序列的string
(21) static String valueof(char[]data, int offset, int count):返回指定数组中表示该字符序列的String
(22) static String copyValueof(char[] data):返回指定数组中表示该字符序列的stritng
(23) static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的String
1.4.5系列5:开头与结尾
(24) boolean startsWith(xx):测试此字符串是否以指定的前缀开始
(25) boolean startsWith(String prefix, int toffset):测试此字符串从指定索引|开始的子字符串是否以指定前缀开始
(26) boolean endsWith(x):测试此字符串是否以指定的后缀结束
1.4.6系列6:替换
(27) String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用newChar替换此字符串中出现的所有oldchar得到的。不支持正则。
(28) String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String s5="abc";
String a=s5.replace("a","wwww");
System.out.println(a);//wwwwbc
(29) String replaceAll(String regex, String replacement):使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串。
(30) String replaceFirst(String regex, String replacement):使用给定的 replacement替换此字符串匹配给定的正则表达式的第一个子字符串。
案例:模拟用户登录
package com.xin.cylei.demo01;
//定义用户类,属性为用户名和密码,提供相关的getter和setter方法,构造器,toString().
public class User {
private String name;
private String password;//密码
public User() {
}
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return name+"-"+password;
}
}
========
package com.xin.cylei.demo01;
import java.util.Scanner;
public class UserTest {
public static void main(String[] args) {
//1.创建数组,并初始化几个User对象
User[] arr=new User[3];
arr[0]=new User("Tom","8888");
arr[1]=new User("songhk","123");
arr[2]=new User("Jerry","6666");
System.out.println("库中的用户有:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
//2.实例化Scanner,获取输入的用户名和密码
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名");
String userName = scanner.next();
System.out.println("请输入密码");
String password = scanner.next();
//3.遍历数组元素,匹配用户名和密码
int i=0;
for ( i= 0; i < arr.length; i++) {
if (arr[i].getName().equals(userName)){//存在此用户名
if (arr[i].getPassword().equals(password)){
System.out.println("登录成功"+userName);
break;
}else {
System.out.println("密码有误");
}
break;
}
}
if (i== arr.length){
System.out.println("没有该用户");
}
scanner.close();
}
}
1.三个类的对比:String、StringBuffer、StringBuilder
- String:不可变的字符序列;底层使用char[] (jdk8及之前),底层使用byte[] (jdk9及之后
- StringBuffer:可变的字符序列; JDK1.0声明,线程安全的,效率低;底层使用char[] (jdk8及之前)﹐底层使用byte[] (jdk9及之后
- StringBuilder:可变的字符序列;JDK5.0声明,线程不安全的,效率高;底层使用char[] (jdk8及之前),底层使用byte[] (jdk9及之后
-
StringBuffer /StringBuilder的可变性分析(源码分析)﹔回顾:
- String s1 = new String(); l/char[] value = new char[0];
- String s2 = new String( "abc"); // char[] value = new char[]{'a' , ' b', 'c'};
针对于StringBuilder来说:内部的属性有:
char[ ] value; //存储字符序列
int count; //实际存储的字符的个数
StringBuilder sBuffer1 = new StringBuilder();
//char[] value = new char[16];
StringBuilder sBuffer1 = new StringBuilder( "abc"); //char[] value = new char[16 + "abc".length]
sBuffer1.append( "ac" ); //value[0] = 'a' ; value[1] = 'c';
sBuffer1.append("b" ) ;//value[2] = 'b ';
...不断的添加,一旦count要超过value.length时,就需要扩容:默认扩容为原有容量的2倍+2并将原有value数组中的元素复制到新的数组中。
3.源码启示:
- 如果开发中需要频繁的针对于字符串进行增、删、改等操作,建议使用StringBuffer或StringBuilder替换String.因为使用String效率低。
- 如果开发中,不涉及到线程安全问题,建议使用StringBuilder替换StringBuffer。因为使用StringBuilder效率高
- 如果开发中大体确定要操作的字符的个数,建议使用带int capacity参数的构造器。因为可以避免底层多次扩容操作,性能更高
2.2 StringBuilder、StringBuffer的API
1、常用API
(1) StringBuffer append(x):提供了很多的append()方法,用于进行字符串追加的方式拼接
(2) StringBuffer delete(int start, int end):删除[start,end)之间字符
(3) stringBuffer deleteCharAt(int index):删除[index]位置字符
(4) StringBuffer replace(int start, int end, String str):替换[start,end)范围的字符序列为str
(5) void setCharAt(int index, char c):替换[index]位置字符
(6) char charAt(int index):查找指定index位置上的字符
(7) StringBuffer insert(int index, xx):在[index]位置插入xx
(8) int length():返回存储的字符数据的长度
(9) StringBuffer reverse():反转
2、其它APl
(1) int indexOf(String str):在当前字符序列中查询str的第一次出现下标
(2) int indexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的第一次出现下标
(3) int lastlndexof(String str):在当前字符序列中查询str的最后一次出现下标
(4) int lastlndexOf(String str, int fromIndex):在当前字符序列[fromindex,最后]中查询str的最后一次出现下标
(5) String substring(int start):截取当前字符序列[start,最后]
(6) String substring(int start, int end):截取当前字符序列[start,end)
(7)String toString(:返回此序列中数据的字符串表示形式
(8) void setLength(int newLength):设置当前字符序列长度为newLength
5.对比三者的执行效率
效率从高到低排列:
StringBuilder > StringBuffer > String
public static void main(String[] args) {
String str = null;
StringBuffer sb = new StringBuffer();sb.append(str);
system.out.println(sb.length();//4
System.out.println(sb); //"null"
StringBuffer sb1 = new StringBuffer(str);System.out.println(sb1);//空指针异常
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?