Stirng对象如何实现
Java6及之前的版本
String对象是对char[]封装进行实现的对象,他的数据主要有四个属性,char[],offset,count,hash,使用count和offset定位char[],获取字符串,可以共享内存空间,节省内存,但是可能引起内存泄露.
Java7,Java8版本
这个版本不在使用count和offset,这样String对象占用内存减少了一些,同时String.subString不在共享char[],从而解决了内存泄露的问题.
Java9版本
这个版本新加了两个属性,byte[],和coder,byte[]替换了之前的char[],而coder仅仅是一个编码表示
Java6为什么会发生内存泄露
因为在这个版本,subString方法会使用new string构造函数,此时会复用char[]数组,我们使用subString方法对一个超大的字符串进行截取一小部分,此时这个subString对应一直被引用,因此超大的字符串就无法进行垃圾回收,这样就会导致内存泄露
Java9这样为什么这个修改
使用byte[]是为了节省内存空间,char占用2个字节,而byte占用一个字节,而使用coder是在计算字符串长度或使用indexOf时候,判断如何计算长度的,coder=0,1,0代表单字节编码latin-1,1代表UTF-16.
String为什么是不可变对象
字符串不可修改防止恶意修改
hash值不可变,保证唯一性
可以实现字符串常量池
字符串对象创建方式
直接使用String str="ab"
这种方式首先会先看常量池是否有值,如果有直接返回引用,如果没有则创建字符串,返回引用给str
使用String str=new String("ab")
这种方式在类编译的时候,字符串在常量池创建,然后使用new String(),同时引用常量池的引用,且在堆中创建一个string对象,再把这个字符串对象引用返回给str.
String对象的优化
创建超大字符串
我们日常开发中经常会拼接字符串,而我们使用+号进行拼接,会不会创建过个对象,导致性能问题呢?
String str="ab"+"cd"+"ef"
实际上编译后的代码仅仅生产了一个对象如下
String str="abcdef"
那么如果我们使用字符串变量累加呢?如下
String str = "abcdef";for(int i=0; i<1000; i++) { str = str + i;}
同样编译优化后如下代码
综合发现,我日常开发中,如果直接显示的使用Stringbuilder进行拼接,来提高系统的性能,如果在多线程下可以使用Stringbuffer,但是如果不考虑使用安全问题,请使用Stirngbuilder,因为Stringbuffer会有锁竞争问题。String str = "abcdef";for(int i=0; i<1000; i++) { str = (new StringBuilder(String.valueOf(str))) .append(i).toString();}
如何使用Stirng.intern节省内存
String a =new String("abc").intern();String b = new String("abc").intern();if(a==b) { System.out.print("a==b");}
运行结果如下
a=b
如果是字符串常量,默认会把对象放到常量池中,如果是字符串变量,会把在堆中创建,同时在常量池创建一个字符串对象,String对象char数组会引用常量池中的char数组,并返回堆内存的引用.
但是如果使用intern,会查看常量池是否有字符串对象的引用,如果有直接返回常量池的引用.
如果没有,在1.6版本中,会把堆中的字符串复制到常量池中,并返回字符串的引用,此时堆中没有指向他的引用,垃圾回收器回收此引用.
如果在1.7版本以后,常量池合并到了堆中,此时不会进行复制字符串,会把堆中的字符串引用添加到常量池中.
如果对您有一丝丝帮助,麻烦点个关注,也欢迎转发,谢谢
扫码关注