解剖String,StringBuffer,StringBuilder三个字符串类型

字符串类型在每种编程语言中都是都是个特殊的存在,因为不管是体积还是数量,字符串都是大多数应用的重要组成部分。下面是一些典型的回答:

String: String是java语言中非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是典型的Immutable类,被声明成final类,所有属性也都是被final修饰的,但是也正是由于String的不可变性,类似拼接,裁剪字符串类型等动作,都会产生新的字符串对象。这样多多少少都会对性能有些影响。

StringBuffer:StringBuffer是为解决上面提到的拼接,裁剪产生太多中间类的问题而提供的一个类。我们可以用append或insert方法来把字符串添加到已有字符串的末尾或指定的位置。StringBuffer由于方法中都用Synchronized修饰,所以是线程安全的,同时又带来了额外的性能方面的开销,如果是在单线程中进行字符串的拼接,建议使用StringBuffer的后继着StringBuilder.

StringBuilder: StringBuilder在能力上是和StringBuffer是没有区别的,无非它是去除了关于线程安全的部分,有效的减少了性能的开销,是大部分时候进行字符串拼接的首选函数。

StringBuffer和StringBuilder的底层都是利用可修改的数组(char,JDK9以后是byte),二者都继承了AbstractStringBuilder,里面包含了基本的操作。那么这个内部数组初始应该为多大呢?目前的实现是构建时初始长度+16(这意味着没有构建对象,没有输入最初长度,长度应该是16),如果确定要拼接的字符串长度的话,构建的时候带上长度,因为扩容会产生多重开销,要抛弃原有数组,创建新的数组(可以简单认为是倍数的数组),还要进行arraycopy。

在日常的编程中,保证程序的可读性,可维护性,往往比所谓的最优性能更重要,可以根据实际需求酌情选择具体的编码方式。

字符串的缓存技术:String在java6提供了intern()方法,目的是提示JVM把相应的字串缓存起来,以备重复使用。在我们创建字符串对象的时候并调用intern()方法的时候,如果已经有缓存的字符串,就会返回缓存的实例,否则就会将其缓存起来。一般来说JVM会将所有类似"abc"这样的文本字符串,或者字符串常量之类缓存起来。虽然提供了intern()方法,但是不建议大量使用intern,为什么呢?魔鬼存在于细节中,在JAVA6这种版本里,被缓存的字符串是存在所谓的PermGen里的,也就是臭名昭著的“永久代”,这个空间是有限的,而且也基本不会被FullGc之外的垃圾收集照顾到,所以一不小心,OutOfMemoryError(OOM内存溢出)会很快光顾的。后续的版本里这个缓存放在堆里,这样就极大的避免了永久代占满的问题,甚至永久代在JAVA8中被MetaSpace(元数据区)取代了,默认的缓存大小也在不断的扩大中,从最初的1009,到7u40以后被修改为60013,intern虽然是一种显示的排重技术,但是要显示的调用,又很难保证效率,开发阶段很难预测到字符重复的情况,有人认为这是一种污染代码的实践。

String自身的演化:

在历史版本中,String字符串是使用char数组来存储数据的,这样非常直接,但是JAVA语言的char是占2个byte的,拉丁语系的字符,根本就不需要太宽的char,这样无区别的实现就会造成了一定的浪费。密度是编程语言平台永恒不变的话题,因为绝大部分的应用是要操作数据的。

在JAVA9中,引用了Compact Strings(紧凑字符串)的设计,对字符串进行大刀阔斧的改进,将数据的存储方式从char数组改变为byte数组和标识编码的所谓的coder,并且将相关字符串操作类都进行了修改。另外所有相关的Intrinsic之类的也都进行了重写,保证没有性能上的损失。

虽然底层进行了这么大的改变,但是JAVA字符串的行为并没有发生太大的改变,所以这个特性对绝大部分应用是透明的,绝大部分不需要修改现有的代码,只要升级JDK版本,就能零成本享受到这些益处。

下面是我使用JDK12关于字符串的一些测试,注意JDK版本不一样,结果可能会有一些细微的差别。

==,equals(),hashcode()三个的不同之处?

==是比较两个对象的引用是否相等

equals()是比较两个字符串的实际值

hashcode()是计算字符串的hash值,两个对象的equals()为true,那么它们的hashcode()值一般情况下也是相等的。


public class TestString {
    public static void main(String[] args) {
		
        String s1 = new String("1111"); 
        String s2 = new String("1111"); 
	String s3 = "1111"; 
        String s4 = "1111"; 
	String s5 = new String("11") + new String("11");
        String s6 = "11" + "11";
		  
        System.out.println(s1 == s2); //false 
        System.out.println(s3 == s4); //true
        System.out.println(s1 == s3); //false 
        System.out.println(s1.equals(s2));//true 
        System.out.println(s1.equals(s3)); //true
	System.out.println(s3.equals(s4)); //true 
        System.out.println(s1.hashCode()); //1508416 
	System.out.println(s2.hashCode()); //1508416
        System.out.println(s3.hashCode()); //1508416
	System.out.println(s4.hashCode()); //1508416 
	System.out.println(s1 == s5);  //false 
	System.out.println(s3 == s5); //false 
        System.out.println(s1 == s6);  //false 
	System.out.println(s3 == s6); //true
	System.out.println(s1.equals(s5)); //true 
	System.out.println(s3.equals(s5)); //true 
	System.out.println(s1.equals(s6)); //true
	System.out.println(s3.equals(s6)); //true 
	System.out.println(s5.hashCode()); //1508416 
	System.out.println(s6.hashCode()); //15081416
		  
    }

}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值