有关于intern()方法入池的问题(jdk1.7及以上)
1.开头说明
我们先来看简单的一段代码,众所周知JAVA中提供了两种String类的实例化方式:
1.直接赋值
String strA = "hello"; //第一种实例化方式
2.通过构造构造方法来实例化
String strB = new String("hello"); //第二种实例化方式
那么我们先来问一个简单的问题:
第二种利用构造方法实例化的方式到底创建了几个对象?
————————————————————————————
————————————————————————————
———————————————————————————>>
答案是两个
这里我们就要引入JAVA中对String类的一些设计了,JAVA对于String设计了一个共享模式,即对象池(String pool),如果采用直接赋值的方式,那么实例化对象即字符串内容直接保存到对象池中。如果下次继续使用直接赋值String对象,如果对象池中含有指定对象,那么直接引用。
↓
↓
构造方法的实例化会创建两个对象:
1."hello"字符串放入对象常量池
2.所创建的String对象
1).String类中“==”比较的含义
我们都知道在数值运算中使用“==”来比较两个对象是否相同。
那么在JAVA中的含义是否一样呢?
String strA = new String("hello");
String strB = new String("hello");
System.out.println(strA == strB);
结果显示的是false。
这里就要引入另一个概念:在JAVA中,== 本身是进行数值比较的,如果现在用于对象比较,那么所比较的就应该是两个对象所保存的内存地址数值比较,并没有比较对象的内容。
1.1)利用刚才的概念验证
我们刚才介绍了对象池的概念,那么现在利用代码来进行验证:
String test = "123";
String test2 = "123";
System.out.println(test == test2);
这时候结果就显示为true,结果表明两个引用指向同一块内存地址。
对象池的意义就在于减少内存的开销。
2.引入intern()方法
如果不是用双引号声明的String对象,可以使用String提供的intern()方法。intern()方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中
3.有关intern()方法细节
先来看一段代码:
String str1 = new String("1");
str1.intern();
String str2 = "1";
System.out.println(str1 == str2);
String str3 = new String("1") + new String("1");
str3.intern();
String str4 = "11";
System.out.println(str3 == str4);
那么结果如何呢?
结果显示:
为什么会产生这样的结果呢?
这就要联系到上文所描述到的构造方法实例化和intern()方法的入池问题。
1)
str1语句本身创建了两个对象:第一个是“1”字符串,并将字符串放入池中;第二个就是所创建的str1对象。
“1”本身就位于池中,从而str1.intern()毫无任何用处。str2所指向的是池中字符串“1”而非str1对象,有因为对象常量池和String对象所处于的heap区位于两个不同区域,所以所指向的内存地址是不可能相同的。
2)
再来看第二段
str3语句所创建了str3对象和两个“1”,此时“1”入池。
**注意此处的str3内容是11,还未入池。
接下来再利用intern()方法入池,发现对象常量池中并未有"11"字符,所以将“11”字符串入池。
str4利用直接赋值,发现对象池中已有“11”字符,直接引用。
所以内存地址指向相同。
利用下图理解更为直观↓
读者可以去参考地址进行更深一步的理解。
参考地址:https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html