常量池

Java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间。常量池其实也就是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。

常量池项共分为11种类型:

常量池项类型 值 说明 
CONSTANT_Utf8 UTF-8编码的Unicode字符串 
CONSTANT_Integer int型常量 
CONSTANT_Float Float型常量 
CONSTANT_Long Long型常量 
CONSTANT_Doubledouble型常量 
CONSTANT_Class  对一个class的符号引用 
CONSTANT_String String型常量 
CONSTANT_Fieldref 对一个字段的符号引用  
CONSTANT_Methodref 10 对一个类方法的符号引用 
CONSTANT_InterfaceMedthodref 11 对一个接口方法的符号引用 
CONSTANT_NameAndType12 对名称和类型的符号引用 

例子1:常量池中对象和堆中的对象

 1 Integer i1 = new Integer(1);
 2 Integer i2 = new Integer(1);
 3 // i1,i2分别位于堆中不同的内存空间
 4 System.out.println(i1 == i2);// 输出false
 5  
 6 Integer i3 = 1;
 7 Integer i4 = 1;
 8 // i3,i4指向常量池中同一个内存空间
 9 System.out.println(i3 == i4);// 输出true
10  
11 // 很显然,i1,i3位于不同的内存空间
12 System.out.println(i1 == i3);// 输出false

例子2:

Java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character 这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。

 1 // 5种整形的包装类Byte,Short,Integer,Long,Character的对象,
 2 // 在值小于127时可以使用常量池
 3 Integer i1 = 127;
 4 Integer i2 = 127;
 5 System.out.println(i1 == i2);// 输出true
 6  
 7 // 值大于127时,不会从常量池中取对象
 8 Integer i3 = 128;
 9 Integer i4 = 128;
10 System.out.println(i3 == i4);// 输出false
11  
12 // Boolean类也实现了常量池技术
13 Boolean bool1 = true;
14 Boolean bool2 = true;
15 System.out.println(bool1 == bool2);// 输出true
16  
17 // 浮点类型的包装类没有实现常量池技术
18 Double d1 = 1.0;
19 Double d2 = 1.0;
20 System.out.println(d1 == d2);// 输出false

例子3:同样的,String也实现了常量池技术

1 // s1,s2分别位于堆中不同空间
2 String str1 = new String("hello");
3 String str2 = new String("hello");
4 System.out.println(str1 == str2);// 输出false
5  
6 // s3,s4位于池中同一空间
7 String str3 = "hello";
8 String str4 = "hello";
9 System.out.println(str3 == str4);// 输出true

例子4:关于Integer类的valueOf方法的一个小问题

1 //代码段A
2 Integer a1 = 127;
3 Integer b1 = 127;
4 System.out.println(a1 == b1);//输出true
5 //代码段B
6 Integer a2 = 128;
7 Integer b2 = 128;
8 System.out.println(a2 == b2);//输出false

原因:当你直接给一个Integer对象一个int值的时候,实际上却自动调用了valueOf方法,然而valueOf方法的内部实现是这样的:

1 public static Integer valueOf(int i) {
2     final int offset = 128;
3     if (i >= -128 && i <= 127) {
4         return IntegerCache.cache[i + offset];
5     }
6     return new Integer(i);
7 }

因为代码段B里赋予的值128溢出了,没有进入if (i >= -128 && i <= 127)条件语句,返回IntegerCache 类的静态数组的数据,IntegerCache类的内部实现是这样的:

1 private static class IntegerCache {
2     private IntegerCache() {
3     }
4     static final Integer cache[] = new Integer[-(-128) + 127 + 1];
5      
6     static {
7         for (int i = 0; i < cache.length; i++)
8             cache[i] = new Integer(i - 128);
9     }

而是直接执行了return new Integer(i)语句,又重新new了一个Integer对象出来,即代码段B实际上就相当于:

1 Integer a2 = new Integer(128);
2 Integer b2 = new Integer(128);

补充说明:关于上文提到的IntegerCache类,由于cache[]在IntegerCache类中是静态数组,也就是只需要初始化一次,即static{……}部分,所以,如果Integer对象初始化时是-128~127的范围,就不需要再重新定义申请空间,都是同一个对象—在IntegerCache.cache中,这样可以在一定程度上提高效率。


例子5:关于String类的intern方法

当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。

它遵循以下规则:对于任意两个字符串s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern()才为true。

例如:

 1 String str1 = new String("abc");
 2 String str2 = str1.intern();
 3 if (str1 == str2) {
 4     System.out.println("字符串abc在常量池中");
 5 } else {
 6     System.out.println("字符串abc不在常量池中");
 7 }
 8  
 9 String str3 = "abc";
10 String str4 = str3.intern();
11 if (str3 == str4) {
12     System.out.println("字符串abc在常量池中");
13 } else {
14     System.out.println("字符串abc不在常量池中");
15 }

还有,

1 String str1 = "abc";
2 String str2 = new String("abc");
3 String str3 = new String("abc");
4 str2.intern();// 不起作用的代码
5 str3 = str3.intern();// 起作用
6 System.out.println(str1 == str2);// 输出:false
7 System.out.println(str1 == str2.intern());// 输出:true
8 System.out.println(str1 == str3);// 输出:true

 

转载于:https://www.cnblogs.com/xianDan/p/4292814.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值