String
String:
重点概念:
-
用来保存字符串,也就是一组字符序列
-
字符串用的是Unicode编码,不管是字母还是汉字都占两个字节
-
字符串构造器很多
-
String类实现了Serializable接口【可以串行化,进行网络传输】
-
String类实现了Comparable接口【String对象可以进行比较】
-
是一个final类,不能被继承
-
底层是实现了一个 char value[]数组**
-
private final char value[];
-
-
final定义就不能被修改了(地址不可修改)
String创建:
- 两种方式
- 直接赋值:String s="abc";直接赋值就是在常量池中
- 调用构造器:String s=new String("ABC");用构造器,会在堆中char数组中保存一个地址指向常量池
public static void main(String[] args) {
String s1 = new String("abc");
String s2="abc";
String s3="abc";
System.out.println(s2.equals(s3));//T
System.out.println(s2 == s3);//T
System.out.println(s1==s2);//F s1指向的是堆中地址(虽然堆中地址里保存的内容指向常量池,但堆中的地址不等于常量池地址),s2指向常量池中地址
System.out.println(s3.intern()==s2);//T
System.out.println(s3.intern()==s1);//F
// intern:在常量池中如果有这个字符串了就返回一个字符串,如果没有就创建字符串并返回地址
person p1 = new person();
person p2 = new person();
System.out.println(p1.name == p2.name);//T,p1和p2指向不同的堆空间,但是里面保存的name是同一个地址都指向同一个常量池,所以相等
}
}
}
String的特性:
public static void main(String[] args) {
// 1.创建了几个对象? 两个
// 重新赋值时,s会判断值改变没有,改变的话就重新创建一个对象,s重新指向这个对象,是不是跟前面说的地址不改变冲突?
// 其实并不是,abc的地址确实没有改变,我们只是修改了s指向的地址而已
String s="abc";
s="bcd";
// 2.创建了几个对象 一个
// 编译器会帮我做优化 变成==》"abcd"
String s1="ab"+"cd";
// 3.创建3个,但是
// ss3创建的时候,执行了3步:stringbuiiler先append:ss1,再append:ss2,最后才和成c并去除多余数据的空间
String ss1="Hello";
String ss2="World";
String ss3=ss1+ss2;
}
小结:1.字符串的修改,不修改内容,会重新生成一个对象,并重新指向
2.字符串的拼接和引用的拼接不同,字符串拼接直接再常量池,而引用会经过Stringbuiller会在堆对象里
470p图看不懂,class内存不太清晰
String常用方法:
- equals //区分大小写,判断内容是否相等
- equalslgnoreCase //忽略大小写的判断内容是否相等
- length /获取字符的个数,字符串的长度
- indexOf //获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1
- lastlndexOf //获取字符在字符串中最后1次出现的索引,索引从开始,如找不到,返回-1
- substring //截取指定范围的子串(左闭右开)
- trim //去前后空格
- charAt:获取某索引处的字符,注意不能使用Str[index]这种方式.
- toUpperCase:大写
- toLowerCase:小写
- concat:拼接
- replace替换字符串中的字符,(本身字符串并没有改变,只是返回的结果改变了)
- split分割字符串,对于某些分割字符,我们需要转义比如| \等
- compareTo //比较两个字符串的大小(继承了Comparable接口)
- toCharArray //转换成字符数组
- format //占位符,%s字符串%c字符%d整型%.2f浮点型
public static void main(String[] args) {
// 1. **equals //区分大小写,判断内容是否相等**
String a1="abccba";
String a2="abccba";
String a3="ABcCBA";
String a4=" avas ";
System.out.println("1: "+a1.equals(a2));;
//2. **equalslgnoreCase //忽略大小写的判断内容是否相等**
System.out.println("2: "+a1.equalsIgnoreCase(a3));
//3. **length /获取字符的个数,字符串的长度**
System.out.println("3: "+a1.length());
//4. **indexOf //获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1**
System.out.println("4: "+a1.indexOf("c"));
//5. **lastlndexOf //获取字符在字符串中最后1次出现的索引,索引从开始,如找不到,返回-1**
System.out.println("5: "+a1.lastIndexOf("a"));
//6. **substring //截取指定范围的子串**
System.out.println("6: "+a1.substring(2));
System.out.println(": "+a1.substring(2,4));
//7. **trim //去前后空格**
System.out.println("7: "+a4.trim());
//8. **charAt:获取某索引处的字符,注意不能使用Str[index]这种方式.**
System.out.println("8: "+a1.charAt(2));
// 9. toUpperCase转成大写
System.out.println("9: "+a1.toUpperCase());
//10. toLowerCase转成小写
System.out.println("10: "+a3.toLowerCase());
//11. concat拼接字符串
System.out.println("11: "+a1.concat(a2));
//12. replace替换字符串中的字符
System.out.println("12: "+a1.replace('a', 'A'));
//12. split分割字符串,对于某些分割字符,我们需要转义比如| \\等
// 以“,”进行分隔
String p = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
String s[]= p.split(",");//会转成一个数组
for (int i = 0; i <p.split(",").length ; i++) {
System.out.println("13: "+s[i]);
}
// 分隔文件地址D:\\e\\a
String p2="D:\\\\e\\\\a";
String P[]= p2.split("\\\\");//这里需要加上\\转义符,不然报错,为什么要加两个因为你有两个\,所以要有两个转义符\
for (String s1:P){
System.out.println("13: "+s1);
}
//14. compareTo //比较两个字符串的大小.前大正数,后大负数,,相等为0 //相同返回0,不同返回差值
System.out.println("14: "+a1.compareTo(a2));
//15. toCharArray //转换成字符数组
char[] chars = a1.toCharArray();
System.out.println(chars);
//16. format //占位符(让字符串变得灵活)
// 1、%s,%d,%.2f,%c称为占位符,占位符由后面变量代替
// 2.%s后面由字符串替换
// 3.%d后面由整数替换
// 4.%.2f由小数替换,并只显示小数后两位
// 5.%c由字符替换
int age=20;
String js="你好,我叫%d,年龄%s";
String name="lc";
String js2=String.format(js,20,name);
System.out.println(js2);
}
StringBuffer:
为什么要有StringBuffer?
- String保存的是字符串常量,前面说过,String类型底层value数组是一个,final修饰的数组,所以每次改变字符串,都会重新生成一个对象再引用,效率低
- 而StringBuffer保存的是字符串变量,底层是一个value数组,没有final修饰,数组在堆里,每次修改字符串,都只修改数组的内容,再指向常量池,不改变地址,效率高
基础特性:
- 直接父类AbstractStringBuilder
- 实现了Serializable,可串行化
- 父类中的char[] value;,存放我们的内容,不是final
- 是一个final类,不能被继承
- 因为StringBuffer底层是char[]数组,每次改变不需要每次更换地址(不说每次都要产生新的对象),所以效率高
构造器:
public static void main(String[] args) {
// 首先会创建一个大小为16的char[]数组
StringBuffer SB = new StringBuffer();
// 自己指定数组的长度
StringBuffer SB2=new StringBuffer(100);
// 此时长度为5+16
StringBuffer SB3=new StringBuffer("Hello");
}
String和StringBuffer的转换:
- Stirng==》StringBuffer
- 放入构造器
- 用append()
- StringBuffer==》String
- tostring()
- 构造器
public static void main(String[] args) {
// Stirng==》StringBuffer
// 放入构造器
String s="Hello";
StringBuffer SB = new StringBuffer(s);
// 第二种用append()
StringBuffer SB2 = SB.append(s);
// StringBuffer==》String
// 第一种tostring
String s1 = SB.toString();
// 第二种构造器
String string = new String(SB2);
}
StringBuffer方法:
- append
- delete
- charAt
- indexOf
- replace
- insert
public static void main(String[] args) {
StringBuffer SB = new StringBuffer();
SB.append("你你好"); //增
SB.delete(1,2); //删
SB.charAt(1); //查
SB.indexOf("好");
SB.replace(0,2,"好的"); //改(替换)
SB.insert(0,"你也"); //插
System.out.println(SB);
}
StringBuilder:
- 跟StringBuffer API兼容,线程不安全(在单线程中使用),但是要比StringBuffer效率高
总结:
-
String
-
每一个字符串中汉字和字母都是两个字节
-
String底层是一个final char [] 的一个数组,被fanal修饰,不能修改地址,所以String是一个常量字符串,当被修改时,就会重新生成一个对象,重新指向
-
实现了Ser接口可以网络传输,实现了comparable重写了比较方法
-
String 自己创建和用构造器创建,直接创建指向常量池,用构造器创建会指向堆里的对象,对象里保存着指向常量池的地址
-
String常用方法:lastindexof,indexof,charat,equals,equal啥,Toup,Tolow,substring,split,format,comparto(实现接口),ToChar(底层是char数组),replace,trim
-
-
StringBuffer
-
上文中说到了String的缺点,那就是每一次修改字符串都会重新指向,效率低,所以就有了StringBuffer
-
底层是一个没有final的char[]数组,添加字符串时会扩容,+16
-
方法:append,delete,replace,indexof,charat,insert
-
和String的转换
-
-
StringBuilder
- 跟StringBuffer兼容一样,线程不安全,单线程时比StringBuffer效率高
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)