下面简单说一下java常量池。我觉得边肖挺好的。我现在就分享给你,给你一个参考。来和边肖一起看看吧。
目录
(1)类常量池(2)运行时常量池
(3)基本类型封装常量池(4)字符串常量池总结java中有几种不同的常量池。下面介绍java中的几个常量池,最常见的是字符串常量池。
(1)class常量池
在Java中,Java类被编译后会形成一个类文件;除了类的版本、字段、方法、接口等描述信息,类文件还包含一个常量池,用来存储编译器生成的各种文字量和符号引用。每个类文件都有一个类常量池。
字面量包括:1。文本字符串;2.价值观的八种基本类型;3.声明为final的常数等。
参考文献包括:1。类和方法的完全限定名;2.字段的名称和描述符;3.方法的名称和描述符。
(2)运行时常量池
运行时常量池存在于内存中,即类常量池加载到内存后的版本,是方法区的一部分(JDK1.8运行时常量池在元空间,也是方法区的一种实现)。不同的是它的字面量可以动态添加(String类的intern()),符号引用可以解析成直接引用。
JVM在执行一个类时,必须进行加载、连接和初始化,连接包括验证、准备和分析三个阶段。当类被加载到内存中时,jvm会将类常量池的内容存储到运行时常量池中。这里说的常量包括:基本类型包装类(包装类不管理浮点类型,整形只管理-128到127)和字符串类型(即可以通过String.intern()方法将String强制放入常量池)。运行时常量池对每个类都是私有的。在解析阶段,符号引用将被直接引用所取代。
(3)基本类型包装类常量池
大多数基本的Java包装类都实现了常量池技术。Byte、short、integer和long是四个包装器类,它们创建相应类型的缓存数据,缺省值为[-128,127]。Character创建值在[0,127]范围内的缓存数据,Boolean直接返回True或False。如果超出相应的范围,将创建一个新对象。Float,Double,两个浮点数类型的包装类,不实现常量池技术。
Integer 缓存源码:
/**
*此方法将始终缓存-128到127(含)范围内的值,并且可以缓存此范围之外的其他值。
*/
(int i)的公共静态整数值{
if(I=integer cache . low I=integer cache . high)
return integer cache . cache[I(-integer cache . low)];
返回新的整数(I);
}
私有静态类IntegerCache {
静态最终int low=-128;
静态最终int高;
静态最终整数缓存[];
}
举个栗子:
整数i1=40
整数i2=40
整数i3=0;
Integer i4=新整数(40);
Integer i5=新整数(40);
Integer i6=新整数(0);
system . out . println(' i1=I2 '(i1==I2));
system . out . println(' i1=I2 i3 '(i1==I2 i3));
system . out . println(' i1=i4 '(i1==i4));
system . out . println(' i4=i5 '(i4==i5));
system . out . println(' i4=i5 i6 '(i4==i5 i6));
system . out . println(' 40=i5 i6 '(40==i5 i6));
结果:
i1=i2真
i1=i2 i3真
i1=i4假
i4=i5错误
i4=i5 i6真
40=i5 i6真
解释:1-4语句的结果应该很明显,因为代码Integer i1=40的那一行会被装箱,也就是说这一行代码相当于Integer i1=Integer.valueOf(40)。整数。基于减少对象创建次数和节省内存的考虑,Value()方法缓存[-128,127]之间的数字。况且直接new,明明40在常量池的cache [-128,127]范围内;因此,i1直接使用常量池中的对象。而Integer i1=new Integer(40)会直接创建一个新对象;语句i4==i5 i6,因为该运算符不适用于整数对象。首先,i5和i6自动拆箱相加,即i4==40。然后Integer对象不能直接和数值比较,i4自动解包,改成int值40。最后这个语句改为40==40进行数值比较,所以结果为真。第六句也一样。
补充说明:所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
对于整数var=?分配介于-128和127之间的值。IntegerCache.cache中生成整数对象,现有对象将被重用。这个区间内的整数值可以用==直接判断,但是这个区间外的数据都会在堆上生成,现有的对象不会被重用。建议用等号法判断。
(4)字符串常量池
在JDK1.6之前,字符串常量池存储在方法区。在JDK1.7之后,字符串常量池被移到堆中。
在HotSpot VM中,记录互联字符串的全局表称为StringTable,本质上是一个HashSetString;在每个HotSpot VM实例中,这个StringTable只有一个副本,由所有类共享。
注意:它只存储对java.lang.String实例的引用,而不存储String对象的内容
字符串常量池与上面的基本类型包装常量池有些不同。有些数据没有提前缓存在字符串常量池中,但如果要创建的字符串存在于常量池中,则返回对象的引用,如果不存在,则创建一个并放入常量池中。
在Java中,创建string对象有两种方法,一种是直接创建literal对象,另一种是创建新的String对象。这两种方法创建string对象的过程会有所不同;
(1)字符串str=' abc
(2)String str=新字符串(' ABC ');
如果它是创建对象的第一种方式,那么它是在编译时确定的,因为它是由字面量直接创建的。如果字符串不在常量池中,它将被放入常量池,并返回字符串对象的引用。如果这是创建对象的第二种方式,字符串对象将在运行时被加载到内存堆中。它属于运行时创建,所以你应该先在堆里创建一个string对象,然后去常量池查找是否有相同的String。如果有,将返回堆中Sring对象的引用,如果没有,将字符串添加到常量池中。
举个栗子:
比较以下两种创建字符串的方法:
String str1=新字符串(' ABC ');
String str2=' abc
答:第一种是用new()创建一个新对象,这个对象会存储在堆中。每次调用都会创建一个新对象。运行时创建。
第二种方法是在堆栈中创建一个对象引用变量str2,然后通过符号引用在字符串常量池中寻找“abc”。如果没有,将“abc”放入字符串常量池,使str2指向“ABC”;如果有“abc”,让str2直接指向“abc”。“abc”在常量池中的存储是在编译期间完成的。
字符串s=新字符串(' abc ')
这条语句创建了多少个对象?
答案:共2个。第一个对象是String对象,它的“abc”字符串存储在常量池中,第二个对象在Java堆中。这里不要混淆s是放在栈中的字符串对象,指向堆Heap。
String s1=新字符串(' S1 ');
String s1=新字符串(' S1 ');
上面创建了多少个对象?
答案:3,编译时在常量池中1,运行时在堆中2。(每个用new创建的new都会在堆上创建一个对象,用引号创建的会直接指向常量池(如果已经存在的话),所以不需要创建。)
总结
本文到此为止。希望能帮到你,也希望你能多关注我们的更多内容!
原文地址:http://www.ccttoo.com/html/1130.html
本文来自网络,不代表菜鸟教程之家立场,转载请注明出处。