【Rookie初学JAVA】
1 常量池
1 .1 class常量池
当class文件被JVM加载进来时存放各种字面量(字符串、被声明为final的常量值、基本数据类型的值)的地方,值得一提的是int类型的字面量的存放有不同的地方。
1.2 运行时常量池
当运行时产生的常量则会被放在运行时常量池,这个是与上面讲到的class常量池分开的,为什么呢?原因就是class常量池是在类加载的时候被放进去的一个区域,其中存放的是写在类体中的内容,而运行时常量池则是在程序运行时产生的常量存放的地方,但是编译期的常量池的内容也可以进入运行时常量池,两者是不同的区域
1.3 字符串常量池的发展
字符串常量池存在运行时常量池之中,在JDK7之前存在运行时常量池之中,在JDK7已经将其转移到堆中
在JDK7中,运行时常量池依旧在方法区内存空间中,而字面量池转移到了java heap即堆中,字符串常量池发生了转移,移动到了堆中。
在JDK8中将运行时常量池也从方法区内存空间中移除了,常量池以元空间代替,元空间使用的也不再是JVM内存,而是本地内存空间。
2 方法区内存空间
3.1 常量池中存在地址
public class Main {
public static void main(String[] args) {
String s1="aaa";
String s2="aaa";
System.out.println(s1==s2);
}
}
/*
运行结果 true
*/
上一篇说过关于“==”是比较两个引用数据类型地址是否相同
public class Main {
public static void main(String[] args) {
String s1="aaa";
String s2=new String("aaa");//在堆中开辟一块新的内存空间
System.out.println(s1==s2);
}
}
/*
运行结果 false
*/
两个结果不同说明了常量池中存放的字符串是有地址的
3.2 整数池
把整数池拿出来是因为他和其他类型的不同
public class Main {
public static void main(String[] args) {
Integer i1,i2;//引用数据类型,单纯的基本数据类型只比较值是否相等
for(int i =-200;i<200;i++){
i1=i;
i2=i;
System.out.println(i+":"+(i1==i2));
}
}
}
/*
运行结果 -128~127 :ture
其余为false
*/
这说明对于Integer 对象,1字节大小以内的值存放在一个相同的区域,这样是为什么呢?为什么会有这种情况的产生?
3 intern()方法
public class Main {
public static void main(String[] args) {
String s1="a";
String s2="b";
String s3=s1+s2;
String s4="ab";
System.out.println(s3==s4);
}
}
/*
运行结果 false
*/
public class Main {
public static void main(String[] args) {
String s1="a";
String s2="b";
String s3=s1+s2;
s3.intern();
String s4="ab";
System.out.println(s3==s4);
}
}
/*
运行结果 true
*/
关于intern()方法:
关于字符串String中的intern方法,是当前的字符对象(通过new出来的对象)可以使用intern方法从常量池中获取,如果常量池中不存在该字符串,那么就新建一个这样的字符串放到常量池中。
package com.pw;
public class Main {
public static void main(String[] args) {
String s1="a";
String s2="b";
String s3=s1+s2;
String s4="ab";
System.out.println(s3==s4);
}
}
/*
运行结果 false
*/
String s3 = s1+s2;这种方式属于字符串中存在变量的拼接方式
此时会创建一个新的String对象
然后创建一个StringBuilder 对象
然后调用StringBuilder的append方法把这两个字符串拼接到一起
最后,通过StringBuilder对象的toString方法返回了一个字符串对象
它是new了一个String对象而且是通过char数组的方式创建的
也就是说不会在字符串常量池中创建对应的字符串
即这种方式创建方式在字符串常量池中不会有新的“ab”。
public class Main {
public static void main(String[] args) {
String s1="a";
String s2="b";
String s3=(s1+s2).intern();
String s4="ab";
System.out.println(s3==s4);
}
}
/*
运行结果 true
*/
public class Main {
public static void main(String[] args) {
String s1="a";
String s2="b";
String s3=s1+s2;
String s4="ab";
s3.intern();
System.out.println(s3==s4);
}
}
/*
运行结果 false
*/
public class Main {
public static void main(String[] args) {
String s1="a";
String s2="b";
String s3=s1+s2;
s3.intern();
String s4="ab";
System.out.println(s3==s4);
}
}
/*
运行结果 true
*/
在这个案例中是否由于以下原因导致s3的地址等于s4的地址:
jdk1.7起,对于intern():如果串池中有,则并不会放入。返回已有的串池中的对象的地址
是否这个返回的地址,对于哪个对象调用就会对于这个对象自动返回常量池中该字符串的地址?
后记:
此篇文章还有待作者去考察验证的想法,虽然目前没有得到相应办法验证,查到的文章也都讲的不是很清晰,但在未来的某一天会进行补充完善。