Java基础-String、StringBuffer、StringBuilder类
String类
String的特性:
-
String 类 代表 字符串。 Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
-
String 是一个 final 类,代表 不 可变的 字符序列 。
-
字符串 是 常量 ,用双引号引起来表示。 它们 的值在创建之后不能更改 。
-
String 对象的字符内容是存储在一个字符 数组 value[] 中 的。
-
String实现了Serializable接口:表示字符串是支持序列化的。
实现了Comparable接口:表示String可以比较大小
-
String:代表不可变的字符序列。简称:不可变性。
体现:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
2. 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
3. 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
-
字符串常量池中是不会存储相同内容的字符串的。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
@Stable
private final byte[] value;
String s1 = "abc";//字面量的定义方式
String s2 = "abc";
s1 = "hello";

String的实例化方式:
-
方式一:通过字面量定义的方式
-
方式二:通过new + 构造器的方式
面试题:
String s = new String("abc");
方式创建对象,在内存中创建了几个对象?
答:两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"
//通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
String s1 = "javaEE";
String s2 = "javaEE";
//通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false

问题 String str1 = "abc"
与 String str2 = new String("abc")
的区别?
字符串常量存储在字符串常量池中,目的是共享。
字符串非常量对象存储在堆中。

字符串对象是如何存储的:
首先会通过 new 在堆空间中开辟一个空间,返回该地址,但对象中value的地址指向常量池中的数据。因此会在内存中创建两个对象。
String s1 = "javaEE";
String s2 = "javaEE";
String s3 = new String("javaEE");
String s4 = new String("javaEE");

Person p1 = new Person("Tom",12);
Person p2 = new Person("Tom",12);
System.out.println(p1.name == p2.name);//true

字符串常量和字符串变量对象的拼接
- 常量与常量的拼接结果在常量池 。 且常量池中不会存在相同内容的常量 。
- 只要其中有一个是变量 ,结果就在堆中。
- 如果拼接的结果调用 intern() 方法,返回值 就 在常量池中。
String s1 = "hello";
String s2 = "world";
String s3 = "hello" + "world";
String s4 = s1 + "world";
String s5 = s1 + s2;
String s6 = (s1 + s2).intern();
System.out.println(s3 == s4);//false
System.out.println(s3 == s5);//false
System.out.println(s4 == s5);//false
System.out.println(s3 == s6);//true

String常用方法



String与基本数据类型转换
-
字符串 -> 基本数据类型、包装类
Integer 包装类的 public static int parseInt (String s):可以将由“数字”字符组成的字符串转换为整型。
类似地 使用 java.lang 包中的 Byte 、 Short 、 Long 、 Float 、 Double 类调相应的类方法。
-
基本数据类型、包装类 -> 字符串
调用 String 类的 public String valueOf int n) 可将 int 型转换为字符串
相应的 valueOf (byte 、 valueOf (long 、 valueOf (float 、 valueOf (double d) 、 valueOf boolean b) 可由参数的 相应 类型到 字符串的转换
String str1 = "123";
//int num = (int)str1;//错误的
int num = Integer.parseInt(str1);
String str2 = String.valueOf(num);//"123"
String str3 = num + "";
System.out.println(str1 == str3);
String 与 char[]之间的转换
- String --> char[]:调用String的toCharArray()
- char[] --> String:调用String的构造器
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.println(charArray[i]);
}
char[] arr = new char[]{'h','e','l','l','o'};
String str2 = new String(arr);
System.out.println(str2);
String 与 byte[]之间的转换
- 编码:String --> byte[]:调用String的getBytes()
- 解码:byte[] --> String:调用String的构造器
编码:字符串 -->字节 (看得懂 --->看不懂的二进制数据)
解码:编码的逆过程,字节 --> 字符串 (看不懂的二进制数据 ---> 看得懂)
说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。
String str1 = "abc123中国";
byte[] bytes = str1.getBytes();//使用默认的字符集,进行编码。
System.out.println(Arrays.toString(bytes));
byte[] gbks = str1.getBytes("gbk");//使用gbk字符集进行编码。
System.out.println(Arrays.toString(gbks));
System.out.println("******************");
String str2 = new String(bytes);//使用默认的字符集,进行解码。
System.out.println(str2);
String str3 = new String(gbks);
System.out.println(str3);//出现乱码。原因:编码集和解码集不一致!
String str4 = new String(gbks, "gbk");
System.out.println(str4);//没有出现乱码。原因:编码集和解码集一致!
StringBuffer和StringBuilder类
String、StringBuffer 和 StringBuilder三者的异同?
String:不可变的字符序列。底层使用char[] 数组进行存储。
StringBuffer:可变的字符序列;线程安全的,效率低。底层使用char[] 数组进行存储。
StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全的,效率高。底层使用char[] 数组进行存储。
源码分析:
//String
String str = new String();//char[] value = new char[0];
String str1 = new String("abc");//char[] value = new char[]{'a','b','c'};
//StringBuffer
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度是16的数组。
System.out.println(sb1.length());// 0
sb1.append('a');//value[0] = 'a';
sb1.append('b');//value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];
问题1 : System.out.println(sb2.length());
sb2的长度是多少?
是3,统计的不是数组的长度,而是添加字符的长度。
问题2:扩容问题:如果要添加的数据底层数组盛不下了,就需要扩容底层的数组。
默认情况下,扩容为原来容量的2倍 + 2,同时将原有数组中的元素复制到新的数组中。
开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)
StringBuffer(StringBuilder)常用方法
StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
StringBuffer insert(int offset, xxx):在指定位置插入xxx
StringBuffer reverse() :把当前字符序列逆转
//以上方法支持方法链操作
//方法链的原理:
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
public int indexOf(String str):返回str在字符串中首次出现的位置
public String substring(int start,int end):返回一个从start开始到end索引结束的左闭右开区间的子字符串
public int length():返回字符串的长度
public char charAt(int n ):取指定位置的字符
public void setCharAt(int n ,char ch):将指定位置的字符改成新的。
总结:
- 增:append(xxx)
- 删:delete(int start,int end)
- 改:setCharAt(int n ,char ch) / replace(int start, int end, String str)
- 查:charAt(int n )
- 插:insert(int offset, xxx)
- 长度:length();
- 遍历:for() + charAt() / toString()
对比String、StringBuffer、StringBuilder三者的效率:
从高到低排列:StringBuilder > StringBuffer > String
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧