字符串(二)

JVM对字符串的处理

JVM为了节省内存,引入了常量池的概念,用来存储可共享的字符串常量,它属于方法区的一部分。

String str1 = new String("字符串");

上面的字符串对象创建语句其实是创建了两个字符串对象,其中一个是"字符串"直接量对应的字符串对象。另外一个是有new String()构造器创建的字符串对象。

对于Java程序中的字符串常量,JVM会使用一个字符串常量池来保存它们:当第一次使用某一个字符串直接量时,JVM会将它放入字符串池进行缓存。在一般情况下,字符串池中的字符串对象不会被垃圾回收,当程序再次需要使用该字符串时,无需重新创建一个新的字符串,而是直接让引用变量指向字符串池中已有的字符串。例如:

public class Test {
	public static void main(String[] args) {
		String str1 = new String("字符串");
		String str2 = "字符串";
		String str3 = "字符串";
		if(str1 == str2) {
			System.out.println("str1与str2指向同一个对象");
		}else {
			System.out.println("str1与str2指向不同的对象");
		}
		if(str2 == str3) {
			System.out.println("str2与str3指向同一个对象");
		}else {
			System.out.println("str2与str3指向不同的对象");
		}
	} 
}

运行结果:
这里写图片描述

从结果可以看到引用str1指向new String()构造器创建的字符串对象,和引用str2指向不同的的字符串对象;而str2和str3都是使用的字符串常量进行创建的,它们都指向字符串池中的"字符串"字符串。

其实,如果一个字符串连接表达式的值可以在编译时确定下来,那么JVM会在编译时计算该字符串变量的值,并让它指向字符串池中对应的字符串。

例如:

public class Test {
	public static void main(String[] args) {
		String str1 = "String字符串";
		String str2 = "String" + "字符串";
		
		if(str1 == str2) {
			System.out.println("str1与str2指向同一个对象");
		}else {
			System.out.println("str1与str2指向不同的对象");
		}
	} 
}

运行结果:
这里写图片描述

上面的str2的值是一个字符串拼接表达式,但是这个字符串连接表达式的值在编译时就能确定下来,因此JVM将在编译时计算str2的值,并让str2指向字符串池中对应的字符串。

那么怎么样的表达式可以在编译时就确定值呢?当表达式中都是直接量(字符串直接量或数值直接量),没有变量参与,没有方法调用时,这个表达式的值就能在编译时确定下来。

所以,当程序中需要使用字符串、基本类型包装类实例时,应该尽量使用字符串直接量、基本类型直接量,避免通过new String()、new Integer()的形式来创建字符串和基本类型包装类的实例,这样能保证较好的性能。

StringBuffer和SringBuilder

StringBuffer和StringBuilder也可以创建字符串,只不过String类是不可变类,创建的是字符串常量,而StringBuffer和StringBuilder是可变的,创建的是字符串变量。

public class Test {
	public static void main(String[] args) {
		String str1 = "字符串";
		StringBuffer str3 = new StringBuffer("StringBuffer");
		
		System.out.println(str3.hashCode());
		str3 = str3.append(str1);
		System.out.println(str3.hashCode());
	} 
}

运行结果:
这里写图片描述

可以看到,str3对象在拼接了str1后并没有指向新的对象。

但是要注意,StringBuffer和StringBuilder不能直接使用字符串直接量进行创建,需要使用new关键字,同时也不能使用运算“+”进行字符串的拼接,当需要拼接字符串的时候,需要调用相应的方法。

同时,StringBuffer是线程安全的StringBuilder是线程不安全的。也就是说StringBuffer类中绝大部分方法都增加了synchronized修饰符,对方法增加synchronized修饰符可以保证该方法线程安全,但是会降低执行效率,所以StringBuilder的性能强于StringBuffer。

总的来说: 少量字符串操作用String; 单线程下操作大量字符串用StringBuilder; 多线程下操作大量字符串用StringBuffer。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值