It's our wits that make us men.

String intern

Posted on By 刘电波

introduction

String intern

一.intern作用

返回一个内容相同的字符串对象,但是该方法保证这个对象是从字符串常量池拿出来的。

1.为什么要用intern:

因为我们很多字符安串操作并不保证结果一定是常量池拿出来的,会导致拿到的对象内容一样(动态拼接,new等等),但是引用不一样,在一些特殊的需求上得不到保证.(例如锁)。

2.什么时候回收:

(1).GC 发现它们不可达,它们将被垃圾回收。

(2).实际上,String对应于字符串文字的对象通常不会成为垃圾回收的候选对象。这是因为在使用字面量的每个方法的代码中都有一个对对象的隐式引用String。这意味着String只要该方法可以执行,就可以访问。

(3).然而,情况并非总是如此。如果在动态加载(例如使用Class.forName(…))的类中定义了字符串文字,则可以安排卸载该类。如果发生这种情况,那么String对应于文字的对象可能无法访问,并且最终可能会被 GC 处理。(字符串动态拼接不进入常量池)。

tips:动态拼接是指不能被编译器优化的,运行时的拼接,它在1.8中会new一个stringbuilder对象来拼接,所以不进入常量池,可以通过字节码技术去验证。

3.缺点是什么:

(1).占用内存,所有字符串都要存在字符串常量池(本来不是所有字符串对象都存在于常量池的)。

(2).存储在hashtable中,数据多了之后,碰撞厉害,而且容易加重full gc负担(这个是网上说的,感觉有一定道理,对象多了肯定是增加gc负担…但是碰撞暂时没办法验证)

二.Interners

 
public class Test {
	private static final Interner<String> pool = Interners.newWeakInterner();

	static void test() {
		synchronized (pool.intern("")) {
		//....
		}
	}
}

(1).上面代码是com.google.common.collect.Interners的使用,针对缺点一,它是可以选择引用强度的,这里选择了弱引用,每次GC该引用指向的对象都会被回收(注意前提是该对象只有这个弱引用指向,没有强引用指向,syn锁住的对象应该有个强引用的,所以不必担心拿到的对象不一致导致锁失效)。

(2).不必新增一份对象进入常量池,减少占用。