理解Java的字符串,String、StringBuffer、StringBuilder有什么区别?
String
1、String的创建机理
由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池。创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接从池中返回此对象的引用,如果没有则新建字符串对象放入池中,并返回引用。但是,通过new方法创建的String对象需要在堆中创建一个对象,如果常量池中有值则不在池中创建,否则在池中再创建一个对象。
2、String的特性
不可变。String对象一旦生成,则不再对它进行改变,不可变的主要作用在于当一个对象被多个线程共享时,可以省略同步和锁的等待时间,提高性能。
针对常量池的优化。当2个String对象拥有相同的值时,他们只引用常量池中的同一个拷贝。
StringBuffer/StringBuilder
StringBuffer和StringBuilder都实现了AbstractStringBuilder抽象类,底层在内存中的存储方式和String一样都是有序的字符序列(char类型的数组),不同的是StringBuffer/StringBuilder对象的值是可以改变的,并且值改变后对象的引用不会发生改变,两个对象在构造过程中,首先按照默认大小16申请一个字符数组,当超过默认数组长度时,会创建一个更大的数组加16,并将原来是内容复制过来,再丢弃旧的数组。
需要注意的是:StringBuffer是线程安全的,它的类中方法都有synchronize关键字。StringBuilder是线程不安全的。所以StringBuilder的性能要高于StringBuffer。
应用场景
1、在字符串内容不经常发生变化的业务场景优先使用String类。
2、在频繁进行字符串的运算,并且运行在多线程环境下,建议使用StringBuffer,如XML解析、HTTP请求参数解析与封装。
3、在频繁进行字符串的运算并且在单线程环境下,建议使用StringBuilder,如SQL语句拼装、JSON封装等。
解析String中intern()方法
String类型的常量池的主要使用方法有两种:
1、直接使用双引号声明出来的String对象会直接存储在常量池中。
2、如果不是双引号声明的String对象,可以使用intern()方法,该方法会从字符串常量池中查询当前字符串是否存在,若不存在就将当前字符串放入常量池中。
分析上面代码:
String s = new String("1"); 创建了两个对象,一个是堆中的String(),一个是常量池中的"1",s在栈中指向堆中的String()对象地址。
s.intern(); s对象去常量池发现"1"已经在常量池,不需要再添加了。
String s2 = "1"; 直接指向常量池中的"1"的地址。
所以s不等于s2。
String s3 = new String("1") + new String("1"); 创建了两个对象,一个是常量池中的"1",一个是JVM优化生成StringBuilder对象完成连接后执行toString方法返回在堆中新对象,s3在栈中指向堆中为"11"的新对象地址。
s3.intern(); 在jdk7中,s3对象去常量池中查找"11",不存在的情况下将堆中"11"的引用存在常量池中,不像jdk6因为Perm区的存在,需要在池中新建一个对象。
String s4 = "11"; s4去池中查找"11",发现存在一个"11"在堆中的引用,返回这个引用。
所以s3等于s4。
网友评论