java 常量池和运行时常量池,java常量池和字符串常量池,Java常量池详解

java 常量池和运行时常量池,java常量池和字符串常量池,Java常量池详解

下面简单说一下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都会在堆上创建一个对象,用引号创建的会直接指向常量池(如果已经存在的话),所以不需要创建。)

总结

本文到此为止。希望能帮到你,也希望你能多关注我们的更多内容!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: