疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

java中String类intern()方法探索


 

 
想到什么写什么,会有点乱,意思理解就行
 
首先我们创建两个字符串对象,如下:
 
String a = new String("hx");
String b = new String("h")+new String("x");
通过new关键字创建字符串对象时,会同时在堆和常量池中生成两个对象,比如说上面的第一条语句产生两个内容均为"hx"的对象,一个在堆中,一个在常量池中,a引用的是堆中的对象,内容是"hx";上面第二条语句产生五个对象,其中两个匿名对象的内容分别是"h"和"x",对应的,常量池中也会生成两个对象,内容分别是"h"和"x",还有一个对象是b引用的,在堆中,内容是"hx";
 
还有一种创建字符串对象的方法,就是直接赋值,如下:
 
1
String c = "hx";
这里,c引用的对象直接放在了常量池中
 
(常量池中内容相同的字符串对象,地址一定是相同的,而堆中不同的对象,地址一定不同)
 
理解上面的内容,然后继续往下看。
 
String类中intern()方法其实也是一个对象的引用(个人理解),引用的对象在常量池中
 
比如先通过new关键字创建字符串对象String s = new String("hx"),变量s引用这个对象,s.intern()方法就是检查常量池中有没有一个内容相同的对象
 
(这里是有的,因为之前说过,通过new关键字会同时创建两个内容相同的对象,一个在堆中,一个在常量池中),
 
若有,则s.intern()引用那个对象,此时(s == s.intern())是false,因为s和s.intern()引用的是两个不同的对象,只是内容相同,地址不同,自然不可能相等;
 
若没有(这种情况我也可以举个例子,String s = new String("h")+new String("x") ,此时常量池中只有两个内容分别为"h"和"x"的对象),则会在常量池中创建一个对象的引用,指向s引用的那个对象(这也是jdk1.7及以后版本与jdk1.6及以前版本的差别,我只探讨最新版本,不多说),说白了就是调用s.intern()方法后,在常量池中出现了一个引用,引用堆中s引用的那个对象(相当于绕了个圈,节省了内存,但时间开销更大),此时(s.intern() ==  s)是true,理由是两者引用的是同一个对象,地址相同,若此时出现这样一条语句String m ="hx",那么(m == s)或者(m == s.intern())就都是true了,因为两者引用了同一个对象,之前说过,常量池中内容相同的对象,地址一定相同,因为之前s.intern()首先在常量池中占了个坑,以后常量池中内容为"hx"的都是引用s.intern()引用的那个对象。
 
下面通过实例说话
 
String a = new String("hx");
System.out.println("1."+(a==a.intern()));
false
 
String a = new String("h")+new String("x");
a.intern();
String b = "hx";
System.out.println("2."+(a==a.intern()));
System.out.println("3."+(b==a));
 
true
 
true
 
String a = new String("hx");
a.intern();
String b ="hx";
System.out.println("4."+(a==b));
System.out.println("5."+(b==a.intern()));
false
 
true
String a = new String("hx");
String b = "hx";
a.intern();
System.out.println("6."+(a==a.intern()));
System.out.println("7."+(b==a.intern()));
false
 
true
 
是否有些头绪了?总之常量池中内容相同的,地址一定相同,谁第一个占坑了(两种占坑方式:intern()方法和直接声明常量,例如String t = "abc"),以后和它内容相同的都引用这个坑没差,重点要理解intern()方法引用的是哪个对象,地址在堆中还是在常量池中,还有一点,intern()方法一定是引用某个对象,绝不会自己创建一个对象然后引用的。
 
最后还有两种情况
 
String a = "h";
String b = "hx"
String c = a+"x";
System.out.println(b==c);
结果是false
 
但如果改一下子,第一条语句加个关键字final
 
final String a = "h";
    String b = "hx";
    String c = a+"x";
    System.out.println(b==c);
结果是true
 
以下纯属个人理解:
 
首先出现这种情况无非就是引用的对象不相同,那第一种情况就是,b引用的对象在常量池中,c引用的对象在堆中;
 
第二种情况是,b和c引用的对象为同一个,均在常量池中。
 
就是final的问题,有这个关键字时,String c = a + "x";在编译时就那啥(描述不来,凑合着理解理解)产生了一个常量放在常量池中,然后发现已经有一个内容相同的了,就直接引用那个的了;没有这个关键字时,String c = a+"x"在运行时才产生结果,这个结果就只能是一个对象了,放在堆中,无法放入常量池中,因为常量池的内容在编译后就确定了,所以c == a自然就是false;
 
然后还有就是为什么一个在编译时就产生结果,一个就在运行时才能产生结果,这得问问final这个关键字了,我也不是很懂..