String、StringBuffer、StringBuilder
一、java.lang.String类的使用
1.概述
String:字符串,使用一对""引起来表示。
1).string声明为final的,不可被继承
2).string实现了Serializable接口:表示字符串是支持序列化的。
实现了Comparable接口:表示String可以比较大小
3).String内部定义了final char[] value用于存储字符串数据
4).通过字面量的方式(区别于new的方式)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
5).字符串常量池中是不会存储相同内容(使用String类的equals()比较,返回true)的字符串的。
2.String的不可变性
2.1说明
1).当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
2).当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
3).当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
2.2代码体现
@Test public void test1(){ String s1 = "abc";//字面量的定义方式 String s2 = "abc"; s1 = "hello"; System.out.println(s1 == s2);//比较s1和s2的地址值 System.out.println(s1); System.out.println(s2); System.out.println("**********************8"); String s3 = "abc"; s3 += "def"; System.out.println(s3); System.out.println(s2); System.out.println("**********************8"); String s4 = "abc"; String s5 = s4.replace('a', 'm'); System.out.println(s4); System.out.println(s5); }
2.3图示

3.String实例化的不同方式
3.1方式说明
方式一;通过字面量定义的方式
方式二:通过new + 构造器的方式
3.2代码演示:
@Test public void test2(){ //通过字面量定义的方式:此时的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 }
3.3面试题
String s = new String("abc");方式创建对象,在内存中创建了几个对象?
两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"
3.4图示:
4.字符串拼接方式赋值的对比
4.1说明
1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中
4.2代码举例
@Test public void test3(){ String s1 = "javaEE"; String s2 = "hadoop"; String s3 = "javaEEhadoop"; String s4 = "javaEE" + "hadoop"; String s5 = s1 + "hadoop"; String s6 = "javaEE" + s2; String s7 = s1 + s2; System.out.println(s3 == s4);//true System.out.println(s3 == s5);//false 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(s6 == s7);//false String s8 = s5.intern();//返回值得到的s8使用的常量值中已经存在的“Java EEhadoop” System.out.println(s3 == s8);
//笔试题
String s1 = "javaEEhadoop";
final String s4 = "javaEE";//常量
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);//true
}
5.常用方法
int length() :返回字符串的长度: return value.length
char charAt(int index) : 返回某索引处的字符return value[index]
boolean isEmpty() :判断是否是空字符串:return value.length == 0
String toLowerCase() :使用默认语言环境,将 String 中的所有字符转换为小写
String toUpperCase() :使用默认语言环境,将 String 中的所有字符转换为大写
String trim() :返回字符串的副本,忽略前导空白和尾部空白
boolean equals(Object obj) :比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString) :与equals方法类似,忽略大小写
String concat(String str) :将指定字符串连接到此字符串的结尾。 等价于用“+”
int compareTo(String anotherString) :比较两个字符串的大小
String substring(int beginIndex) :返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
boolean endsWith(String suffix) :测试此字符串是否以指定的后缀结束
boolean startsWith(String prefix) :测试此字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset) :测试此字符串从指定索引开始的子字符串是否以指定前缀开始
boolean contains(CharSequence s) :当且仅当此字符串包含指定的 char 值序列时,返回 true
int indexOf(String str) :返回指定子字符串在此字符串中第一次出现处的索引
int indexOf(String str, int fromIndex) :返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
int lastIndexOf(String str) :返回指定子字符串在此字符串中最右边出现处的索引
int lastIndexOf(String str, int fromIndex) :返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
注:indexOf和lastIndexOf方法如果未找到都是返回-1
String replace(char oldChar, char newChar) :返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
String replace(CharSequence target, CharSequence replacement) :使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String replaceAll(String regex, String replacement) : 使 用 给 定 的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
String replaceFirst(String regex, String replacement) : 使 用 给 定 的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。匹配
boolean matches(String regex) :告知此字符串是否匹配给定的正则表达式切片
String[] split(String regex) :根据给定正则表达式的匹配拆分此字符串。
String[] split(String regex, int limit) :根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中
6.String与其他结构的转换
6.1与基本数据类型、包装类之间的转换
String ---> 基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)
基本数据类型、包装类 ---> String:调用String重载的valueOf(xxx)
*/
@Test
public void test1(){
String str1 = "123";
int num = Integer.parseInt(str1);
String str2 = String.valueOf(num);
}
6.2与字符数据之间的转换
String ---> char[]:调用String的toCharArray()
char[] ---> String :调用String的构造器
*/
@Test
public void test2(){
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'};
String str2 = new String(arr);
System.out.println(str2);
}
6.3与字节数组之间的转换
编码:String ---> byte[]:调用String的getBytes()
解码:byte[] ---> String:调用String得构造器
编码:字符串 ---->字节 (看得懂 ---->看不懂得二进制数据)
解码;编码得逆过程,字节 ---> 字符串(看不懂得二进制数据 --->看得懂)
说明:解码时,要求解码使用得字符集必须与编码时使用得字符集一致,否则会出现乱码。
@Test
public void test3() throws UnsupportedEncodingException {
String str1 = "abc123中国";
byte[] bytes = str1.getBytes();//使用默认的字符集,进行转换
System.out.println(Arrays.toString(bytes));
byte[] gbks = str1.getBytes("gbk");//使用默认的字符集,进行转换
System.out.println(Arrays.toString(gbks));
System.out.println("***************88");
String str2 = new String(bytes);//使用默认的字符集,进行转换
System.out.println(str2);
String str3 = new String(gbks);
System.out.println(str3);//出现乱码。原因:编码集和解码集不一致!
String gbk = new String(gbks, "gbk");
System.out.println(gbk);
}
6.4与StringBuffer、StringBuilder之间的转换
String -->StringBuffer、StringBuilder:调用StringBuffer、StringBuilder构造器
StringBuffer、StringBuilder---->String:①调用String构造器;②StringBuffer、StringBuilder的toString()
7.常见算法题目:
public class StringDemo { /* 将一个字符串进行反转。将字符串中指定部分进行 反转 。比如“abcdefg” 反 转为”abfedcg” 方法一:转换为char[] */ public String reverse(String str,int startIndex,int endIndex){ if (str != null){ char[] arr = str.toCharArray(); for (int x = startIndex,y = endIndex;x < y;x++, y--){ char temp = arr[x]; arr[x] = arr[y]; arr[y] = temp; } return new String(arr); } return null; } //方式二:使用String的拼接 public String reverse1(String str,int startIndex,int endIndex){ if (str != null){ String reverseStr = str.substring(0,startIndex); for (int i = endIndex; i >= startIndex; i--) { reverseStr += str.charAt(i); } reverseStr += str.substring(endIndex + 1); return reverseStr; } return null; } //方法三:使用StringBuffer/StringBuilder替换String public String reverse2(String str,int startIndex,int endIndex){ if (str != null){ StringBuilder builder = new StringBuilder(str.length()); builder.append(str.substring(0,startIndex)); for (int i = endIndex; i >= startIndex; i--) { builder.append(str.charAt(i)); } builder.append(str.substring(endIndex + 1)); return builder.toString(); } return null; } @Test public void testReverse(){ String str = "abcdefg"; String reverse = reverse(str, 2, 5); System.out.println(reverse); } }
public class StringDemo1 { /* 获取一个字符串在另一个字符串中出现的次数。 比如:获取“ ab” 在 “abkkcadkabkebfkabkskab” 中 出现的次数 */ /** * 获取subStr在mainStr中出现的次数 * @param mainStr * @param subStr * @return */ public int getCount(String mainStr,String subStr){ int mainLength = mainStr.length(); int subLength = subStr.length(); int count = 0; int index = 0; if (mainLength >= subLength){ //方式一 // while ((index = mainStr.indexOf(subStr)) != -1){ // count++; // mainStr = mainStr.substring(index + subStr.length()); // } //方式二: while ((index = mainStr.indexOf(subStr,index)) != -1){ count++; index += subLength; } return count; }else { return 0; } } @Test public void testGetCount(){ String mainStr = "abkkcadkabkebfkabkskab"; String subStr = "ab"; System.out.println(getCount(mainStr,subStr)); } }
public class StringDemo2 { /* 获取两个字符串中最大相同子串。比如: str1 = "abcwerthelloyuiodef“;str2 = "cvhellobnm" 提示:将短的那个串进行长度依次递减的子串与较长的串比较。 */ //前提:两个字符串中只有一个最大相同字串 public String getMaxSameString(String str1,String str2){ if (str1 != null && str2 != null){ String maxStr = (str1.length() >= str2.length())? str1:str2; String minStr = (str1.length() < str2.length())? str1:str2; int length = minStr.length(); for (int i = 0;i < length;i++){ for (int x = 0,y = length - i;y <= length;x++, y++){ String subStr = minStr.substring(x,y); if (maxStr.contains(subStr)){ return subStr; } } } } return null; } @Test public void testGetMaxSameString(){ String str1 = "abcwerthelloyuiodef"; String str2 ="cvhellobnm"; System.out.println(getMaxSameString(str1,str2)); } }
二、StringBuilder、StringBuffer
1.String、StringBuffer、StringBuilder三者的异同?
String:不可变的字符序列:底层使用char[]存储
StringBuffer:可变的字符序列:线程安全的,效率低,底层使用char[]存储
StringBuilder:可变的字符序列:jdk5.0新增的,线程不安全的,效率高,底层使用char[]存储
2.StringBuffer与StringBuilder的内存解析
以StringBuffer为例
String str = new String();//new char[0];
String str1 = new String("abc");//new char[]{'a','b','c'};
System.out.println(sb1.length());//0
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度是16的数组。
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());//3
//问题2.扩容问题:如果要添加的数据底层数据盛不下了那就需要扩容底层的数据。
默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中。
指导意义:开发中建议大家使用:StringBuffer(int capacity)或StringBuilder(int capacity)
3.对比String、StringBuffer、StringBuilder三者的执行效率
从高到底排列:StringBuilder > StringBuffer > String
4。StringBuffer、StringBuilder的常用方法
增: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()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)