常量池&八种基本类型的包装类和对象池&字符串常量池分析及示例
2022-03-10 19:06:54 0 举报
大白话常量池
作者其他创作
大纲/内容
public static void main(String[] args) { String a=new String(\"abc\")+new String(\"def\"); //在调用intern前加上这行就返回false。因为这样是先把abcdef放到字符串常量池 //再调用intern就返回字符串常量池中的abcdef的引用 //String c=\"abcdef\"; String b=a.intern(); System.out.println(a==b); //在调用第一次调用intern前不加,在调用一次intern后加上这行仍然为true。 //因为这样是在之前调用intern时, // 就把 堆中的abcdef对象 的引用放到字符串常量池了 //现在再定义abcdef,其实只是将字符串常量池中的引用 指向 c String c=\"abcdef\"; String d=a.intern(); System.out.println(a==c); System.out.println(a==d); System.out.println(c==d); }
注意:如果是jdk1.6的版本,则不一样,因为当堆里的abcdef对象创建后,如果常量池中没有abcdef字符串对象,就会自动复制一份到字符串常量池。因此再比较时,就是常量池中的字符串对象与堆对象的比较,结果为false。
进阶版
缘由
注意一些特殊的字符串,比如关键字java是默认放到字符串常量池的。
这种直接定义的基础数据类型,其实转成字节码文件后,是调用valueOf方法来实现的。
/**启动参数 * jdk6有永久代:-Xms6M -Xmx6M -XX:PermSize=6M -XX:MaxPermSize=6M * jdk8元空间:-Xms6M -Xmx6M -XX:MetaspaceSize=6M -XX:MaxMetaspaceSize=6M* jdk8:报错是 java.lang.OutOfMemoryError: Java heap space 说明字符串常量池在堆里 */public class RuntimeConstantPoolOOM { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); for (int i = 0; i < 10000000; i++) { String str = String.valueOf(i).intern(); list.add(str); } }}
字符串常量池:底层类似一个 HashTable,K:V的格式, 保存的本质上是常量池字符串对象的引用:字符串对象。对象都是在编译时放入的,或者在创建字符串对象后,会自动将其字符串放入。
验证代码
主要包括 三类常量:类和接口的全限定名字段的名称和描述符方法的名称和描述符
字面量就是指由字母、数字等构成的字符串或者数值常量
首先是在堆里创建了abc和def的字符串对象,又创建了abc,def常量池对象,然后创建堆里的abcdef对象。然后因为常量池中没有abcdef对象,所以直接返回abcdef的指向.然后才将abcdef放到常量池。
这种方式创建的字符串对象,只会在常量池中。因为有\"abc\"这个字面量,创建对象s的时候,JVM会先去常量池中通过 equals(key) 方法,判断是否有相同的对象如果有,则直接返回该对象在常量池中的引用;如果没有,则会在常量池中创建一个新对象,再返回引用。
八种基本类型的包装类和对象池
Integer的范围可以通过-XX:AutoBoxCacheMax来调整。此JVM参数就是修改Integer的high值。
Boolean类是true和false加载类的时候就会放到对象池中return (b ? TRUE : FALSE);public static final Boolean TRUE = new Boolean(true);public static final Boolean FALSE = new Boolean(false);
字面量只可以右值出现,所谓右值是指等号右边的值如:int a=1 这里的a为左值,1为右值。在这个例子中1就是字面量。
static final Character cache[] = new Character[127 + 1];static { for (int i = 0; i < cache.length; i++) cache[i] = new Character((char)i);}
1、字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能2. JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化为字符串开辟一个字符串常量池,类似于缓存区创建字符串常量时,首先查询字符串常量池是否存在该字符串存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中.
int a=1;的a,就是字段名称,就是一种符号引用,还有Math类常量池里的 Lcom/tuling/jvm/Math 是类的全限定名,main和compute是方法名称,()是一种UTF8格式的描述符,这些都是符号引用。这些常量池现在是静态信息,只有到运行时被加载到内存后,这些符号才有对应的内存地址信息,这些常量池一旦被装入内存就变成运行时常量池,对应的符号引用在程序加载或运行时会被转变为被加载到内存区域的代码的直接引用,也就是我们说的动态链接了。例如,compute()这个符号引用在运行时就会被转变为compute()方法具体代码在内存中的地址,主要通过对象头里的类型指针去转换直接引用。
通过例题解析字符串常量池
直接赋值字符串
String s1=new String(\"abc\")+new String(\"def\");String s2=a.intern();这里就是返回新拼接的对象的引用,所以S1==S2
public static void main(String[] args) { String a = \"a3.4\"; String b = \"a\" + 3.4; /** * JVM对于字符串常量的\"+\
符号引用
Character:char 内存存储二进制位数:16
intern方法
首先是在堆里创建对象abc,常量池创建对象abc,s1指向abc。s1调用intern方法,因为常量池中有abc,因此返回常量池中abc。
Boolean
// s指向常量池中的引用String s = \"abc\";
字面量
java.lang.Integer#valueOf(int)java.lang.Short#valueOf(short)java.lang.Long#valueOf(long)都会先判断是否是-128到127内的。因为这些类都有个静态常量数组:integer是cache = new Integer[(high - low) + 1];static final Short cache[] = new Short[-(-128) + 127 + 1];static final Long cache[] = new Long[-(-128) + 127 + 1];
这种方式会保证字符串常量池和堆中都有这个对象,没有就创建,最后返回堆内存中的对象引用。步骤大致如下:因为有\"abc\"这个字面量,所以会先检查字符串常量池中是否存在字符串\"abc\"不存在,先在字符串常量池里创建一个字符串对象;再去内存中创建一个字符串对象\"abc\";存在的话,就直接去堆内存中创建一个字符串对象\"abc\";最后,将内存中的引用返回。
String s1 = new String(\"abc\");String s2 = s1.intern();这里就是返回池中的字符串,所以S1!=S2
// s1指向内存中的对象引用String s1 = new String(\"abc\");
位置
区分堆对象还是字符串常量池对象,启动编译期是否能确定值。
new String();
IntegerShortLong
三种字符串操作-Jdk1.8
public static void main(String[] args) { //new 创建的字符串对象不是常量,不能在编译的时候确认, //因此下面三个都是堆里的新对象,都有各自的地址,但都指向字符串常量池中的aaa对象 String a=new String(\"aaa\"); String a2=new String(\"aaa\"); //这个对象后半部分无法在编译器确定,因此也是新创建的堆对象 String b=\"aa\"+new String(\"a\"); //常量,在编译期就确定的,放在常量池中,存的是常量池中aaa的引用 String c=\"aaa\";//字符串常量池的aaa对象 System.out.println(a==b);//false System.out.println(c==b);//false System.out.println(a==a2);//false }
常量池(constant pool table),用于存放编译期生成的各种字面量(Literal)和符号引用(Symbolic References)。常量池中主要存放两大类常量:字面量和符号引用。
0 条评论
下一页