【知晓的丧day拯救计划】java基础学习笔记补充 String相关类

String类、StringBuilder类、StringBuffer类是三个字符串相关类,String类对象是不可变字符序列,后两者是可变字符序列,StringBuilder效率高但线程不安全,StringBuffer效率低但线程安全。

String

String类对象是不可变字符序列,位于java.lang包中。
在String类中存放字符串的数组是由final修饰的常量,说明其只可以被初始化一次,赋值之后再对该String对象进行操作(截取替换等),得到的都是一个新的字符串,原字符串不会发生改变。

创建String对象

字面量创建String对象

String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);		 //true
System.out.println(s1.equals(s2));   //true

堆内存中有一个单独的部分叫做字符串常量池。
执行String s1 = “hello”;时,常量池中添加"hello"对象,返回引用地址给s1对象
执行String s2 = “hello”;时,通过equals()方法判断常量池中是否已有值为"hello"的对象,若有,直接返回引用地址。
可以看出这样的机制下,s1和s2指向相同,所以执行"==" 和equals,结果都是true。

new创建String对象

String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s3 == s4);		  //false
System.out.println(s3.equals(s4));    //true

执行String s3 = new String(“abc”);时,在常量池中添加"abc"对象,在堆中创建值为"abc"的对象s3,返回指向堆中s3的引用。
执行String s4 = new String(“abc”);时,常量池中已经有值为"abc"的对象,不做处理,在堆中创建值为"abc"的对象s4,返回指向堆中s4的引用。
可以看出s3和s4引用的是不同的对象,所以==判断为false,String类型是equals方法特例,所以结果是true。

综上,用字面量创建字符串对象时,只在常量池创建对象,用new的时候,在常量池和堆内存中都创建了对象,所以字面量方式更加省内存。

字面量方式相加
String s5 = “x” + “y”;
执行时,经过JVM优化,直接在常量池中添加"xy"对象。
但是JVM只可以判断字符串常量,如果是变量相加则无法优化。

String str1 = "hello" + "world";
String str2 = "helloworld";
String str3 = "hello";
String str4 = "world";
String str5 = str3 + str4;
System.out.println(str1 == str2);  //true
System.out.println(str2 == str5);  //false

new方式相加
String s6 = new String(“1”) + new String(“1”) + new String(“2”);
通过StringBuilder实现,先在常量池中添加"1"对象,第二个1时因为常量池中存在所以不操作,再在常量池中添加"2"对象,然后在堆中创建值为"112"的对象,给s6返回指向堆中"112"对象的引用。

String类常见方法

方法
char charAt(int index)返回字符串中第index位置的字符,范围0~length-1
boolean equals(String other)如果字符串和other相等,返回true,否则返回false
boolean equalsIgnoreCase(String other)忽略英文大小写判断字符串是否相等
int indexOf(String str)返回从头开始查找子字符串str在字符串在的索引,没有则返回-1
int lastIndexOf(String str)返回从末尾开始查找子字符串str在字符串在的索引,没有则返回-1
int length()返回字符串长度
String replace(char oldChar,char newChar)返回一个由newChar替换oldChar的新字符串
boolean startsWith(String prefix)如果字符串以prefix开始,返回true
boolean endsWith(String prefix)如果字符串以prefix结束,返回true
String subString(int beginIndex)返回一个新字符串,截取从字符串beginIndex到字符串结尾
String subString(int beginIndex,int endIndex)返回一个新字符串,截取从字符串beginIndex到endIndex-1
String toLowerCase()返回一个新字符串,将原字符串所有大写字母改成小写
String toUpperCase()返回一个新字符串,将原字符串所有小写字母改成大写
String trim()删除字符串中头部和尾部的空格
String str = "123strabcdstrXYZ";
		
//charAt
System.out.println(str.charAt(2));  //3
System.out.println(str.charAt(str.length()-1));  //Z
		
//indexOf
System.out.println(str.indexOf("str"));  //3
System.out.println(str.lastIndexOf("str")); //10
System.out.println(str.indexOf("df")); //-1
		
//replace
System.out.println(str.replace('r', 'u'));  //123stuabcdstuXYZ
System.out.println(str.replace("str", "HELLO")); //123HELLOabcdHELLOXYZ
		
//startsWith、endsWith
System.out.println(str.startsWith("23")); //false
System.out.println(str.endsWith("YZ"));  //true
		
//subString
System.out.println(str.substring(5)); //rabcdstrXYZ
System.out.println(str.substring(5, 10));  //rabcd
		
//toUpperCase、toLowerCase
System.out.println(str.toUpperCase());  //123STRABCDSTRXYZ
System.out.println(str.toLowerCase());  //123strabcdstrxyz
		
//trim
String str1 = "\ta  bc   ";
System.out.println("*" + str1 + "*");  //*	a  bc   *
System.out.println("*" + str1.trim() + "*");  //*a  bc*

StringBuilder和StringBuffer

StringBuilder和StringBuffer都是可变字符序列,保存其对象的数组是变量。
一般不涉及线程问题时,建议采用StringBuilder,因为它的效率更高。

StringBuilder和StringBuffer常用方法

StringBuilder和StringBuffer都继承了抽象类AbstractStringBuilder,所以常用方法都相同。

方法作用
StringBuilder append()在StringBuilder对象末尾添加字符串序列,返回自身对象
StringBuilder delete(int start, int end)删除StringBuilder对象从索引start到end-1的字符串,返回自身对象
StringBuilder deleteCharAt(int index)删除StringBuilder对象索引为index的的字符,返回自身对象
StringBuilder insert()在StringBuilder对象指定位置插入字符串序列,返回自身对象
StringBuilder reverse()用于逆序排列字符串,返回自身对象
String toString()将StringBuilder对象中的数据以String类表示

此外,还有String类类似的方法:indexOf、subString、length、charAt等。

StringBuilder sb1 = new StringBuilder();
//在StringBuilder对象末尾添加字符串序列
sb1.append(123);
System.out.println(sb1);  //123
//因为返回其本身,所以可以连续调用
sb1.append("a").append("b").append("c");  
System.out.println(sb1);  //123abc
		
//插入
sb1.insert(0, "va").insert(0, "ja");
System.out.println(sb1);  //java123abc
		
//删除
sb1.deleteCharAt(4).deleteCharAt(5);  
System.out.println(sb1);  //java2abc
sb1.deleteCharAt(4).delete(0, 4);
System.out.println(sb1);  //abc
		
//逆序
System.out.println(sb1.reverse());  //cba

String使用陷阱

我们知道了String是不可变字符串
所以当我们执行String s = “a”;s = s + “b”;时,s指向了新字符串对象"ab",而原来的字符串对象"a"就被废弃了,如果多次进行这样的操作,就会导致大量字符串对象留存在内存中,降低效率。

//进行大量字符串拼接时

//使用String类拼接
String str11 = "";
long num1 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
long time1 = System.currentTimeMillis();//获取系统当前时间		
for(int i = 0; i < 5000; i++) {
	str11 = str11 + i; //相当于产生了5000个对象
}		
long num2 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
long time2 = System.currentTimeMillis();//获取系统当前时间
		
System.out.println("String占用内存:" + (num1 - num2));
System.out.println("String占用时间:" + (time2 - time1));

//使用StringBuilder类拼接		
StringBuilder sb11 = new StringBuilder();		
long num3 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
long time3 = System.currentTimeMillis();//获取系统当前时间		
for(int i = 0; i < 5000; i++) {
	sb11.append(i);
}		
long num4 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
long time4 = System.currentTimeMillis();//获取系统当前时间
		
System.out.println("StringBuilder占用内存:" + (num3 - num4));
System.out.println("StringBuilder占用时间:" + (time4 - time3));

/* 运行结果
* String占用内存:4086616
* String占用时间:51
* StringBuilder占用内存:524288
* StringBuilder占用时间:0
*/

所以,在做大量字符串修改时,要避免使用String类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值