avatar

目录
JVM:关于方法区、永久代、常量池、String的intern()

方法区和永久代

方法区:是JVM的一种规范,存放类信息、常量、静态变量、即时编译器编译后的代码等;

永久代:是HotSpot的一种具体实现,实际指的就是方法区

常量池和永久代

jdk1.6及之前版本:常量池分配在永久代中

jdk1.7之后:常量池分配在java堆中

001

String#intern()方法

intern方法会先去查询常量池中是否有字符串已经存在,如果存在,则返回常量池中的引用,这一点jdk1.6、jdk1.7一样

区别在于,如果在常量池找不到对应的字符串:

jdk1.6 会再将字符串拷贝到常量池,返回指向常量池的引用。

jdk1.7 则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串(java堆中)的引用。

简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。

String对象与常量池

java
1
2
3
4
5
6
/*String s1 = new String(“abc”)做了如下事情:
1、在常量池中创建了“abc”
2、在java堆中创建了new String(“abc”)对象,该对象指向常量池的“abc”
3、在java栈中创建了s1引用,指向java堆中的对象
如下图
*/

002

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

public class StrTest {

public static void main(String[] args) {
/*
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2); //true,均指向常量池中对象
*/

/*
String s1 = new String("abc");

String s2 = new String("abc");
System.out.println(s1 == s2); //false,两个引用指向堆中的不同对象
*/

/*
String s1 = "abc";
String s2 = "a";
String s3 = "bc";
String s4 = s2 + s3;
String s5 = s2 + s3;
System.out.println(s1 == s4); //false,因为s2+s3实际上是使用StringBuilder.append来完成,会生成不同的对象
System.out.println(s4 == s5); //false,StringBuilder.append在堆中生成不同的对象
*/

/*
String s1 = "abc";
final String s2 = "a";
final String s3 = "bc";
String s4 = s2 + s3;
System.out.println(s1 == s4); //true,因为final变量在编译后会直接替换成对应的值,所以实际上等于s4=”a”+”bc”,而这种情况下,编译器会直接合并为s4=”abc”,所以最终s1==s4
*/

/*
String s = new String("abc");
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s == s1.intern()); //false,"abc"在常量池中已存在,s1.intern()指向常量池的字符串。而s指向堆中的字符串对象
System.out.println(s == s2.intern()); //false,同理
System.out.println(s1 == s2.intern()); //true,
*/

/*
String str1 = new StringBuilder("a").append("bc").toString(); //会在常量池生成"a"、"bc",在堆区生成"abc"对象,返回给str1
System.out.println(str1.intern() == str1);//true,str1.intern()在常量池中没找到"abc",jdk1.7之后会在常量池生成一个引用指向堆区的"abc"对象

String str2 = new StringBuilder("ja").append("va").toString();//在堆区生成"java"对象
String str3 = new StringBuilder("ja").append("va").toString();
System.out.println(str2 == str3);//false
System.out.println(str2.intern() == str2);//false。str2.intern()在常量池中找到了"java",则str2.intern()指向的是常量池的"java"
//常量池中为什么会存在"java"这样的字符串?
//类加载等操作使"java"字符串加入到了常量池中
*/
}
}
文章作者: Machine
文章链接: https://machine4869.gitee.io/2018/11/14/20181114220123030/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论