1. 运行时常量池属于线程共享区中的方法区
2. 运行时常量池用于编译期生成的各种自变量, 符号引用, 这部分内用将在类加载后接入方法区的运行时常量池中存放
看如下代码所示, 如图:
- public class Test {public static void main(String[] args) {
- String s1 = "abc";
- String s2 = "abc";
- String s3 = new String("abc");
- System.out.println(s1 == s2);
- System.out.println(s1 == s3);
- }
- }
很明显 s1 == s2 为 true, 而 s1 == s3 为 false
因为基本数据类型和抽象数据类的引用是放在栈帧的局部变量表中所以 s1 s2 是放在栈帧的局部变量表中而 abc 这个对象则是放在运行时常量池中
而这个常量池有钟数据结构叫 Stringtable, 它的数据类型可以理解为 HashSet 而 HashSet 是无序的, 不可重复的因此第一次将定义的 abc" 放入其中
而第二次定义中发现常量池中有 abc 了, 则不再创建 abc" 了, 此时 s1 和 s2 则引用的是同一个 abc 因此 s1 == s2 为 true
而 s3 则是通过 new 出来的实例, 则放进 java 堆中, 此时 s3 引用的是堆中的 abc" 因此 s1 == s3 为 false
如果将 s3 变动一下又会产生什么结果呢? 如下代码所示:
- public class Test {
- public static void main(String[] args) {
- String s1 = "abc";
- String s2 = "abc";
- String s3 = new String("abc");
- System.out.println(s1 == s2);
- System.out.println(s1 == s3);
- System.out.println(s1 == s3.intern());
- }
- }
很明显 System.out.println(s1 == s3.intern()); 为 true 因为 s3.intern() 是将堆中的 abc" 拿出来放进常量池中, 而常量池中已经存在 abc, 因此直接把常量池中的
abc" 引用给了 s3, 因此 System.out.println(s1 == s3.intern()); 为 true, 这就形成了运行时常量
注意当常量池中满了同样会抛出 OutOfMemory 内存溢出异常
这里顺便提提一个叫做直接内存
直接内存: 并不是虚拟机运行时数据区的的一部分当然了, 这也不是虚拟机规范中定义的内存 区域而是一种对外的内存区域
NIO 正是经常用到了对外内存同样当对外内存满了也照样会抛出 OutOfMemory 内存溢出异常抛出这种异常也要考虑一下这个区域
来源: http://www.bubuko.com/infodetail-2499479.html