java中的常量池技术

先用一个问题引入常量池技术。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class Test2 {  
  2.   
  3.     public static void main(String[] args) {  
  4.           
  5.         String s1="Hello Java";  
  6.         String s2="Hello Java";  
  7.         String s3=new String("Hello Java");  
  8.         System.out.println(s1==s2);//①  
  9.         System.out.println(s3==s2);//②  
  10.   
  11.     }  
  12.   
  13. }  

问:①处的结果是多少?②处的结果是多少?很多初学者被这个问题弄的一头雾水。在java中像这样的问题还有其他的,比如说int与Integer(后面会提到这个)。这些都跟java的常量池有关。

什么是常量池?

常量池说白了就是一块内存区域,这块内存会对一些对象进行缓存,在需要的时候直接将其地址复制给变量,以达到加快效率,节省空间的作用。不仅String类具有常量池技术,而且大部分基本数据类型的包装类(Integer,long,short,byte,Character,Boolean)都实现了包装类。

常量池有什么作用?

常量池将一个类中的字符或者基本数据类型放入缓冲区(各自的常量池)中,如果程序后来想再创建此类对象,则可以直接生成,不需要new一个,这样可以节省时间和空间。

一:字符串常量池

接下来,我将常量池分成两部分,一部分是常见的String的常量池,叫做字符串常量池。这个常量池会存储类中已经初始化的字符串。举个例子:定义一个hello的字符串String  s  = “hello”;,虚拟机的工作原理是:首先在字符串常量池中寻找有没有“hello”,如果找到了,就将此字符串的地址赋值给s,如果没有找到,就会创建一个(new一个)新的字符串,当程序想创建第二个字符串“hello”的时候,就会直接将此地址赋值给新的变量。所以上面的程序①处输出true。

如果 程序是使用new来创建一个字符串的时候,会直接在堆内存中创建一个字符串对象。所以程序②处输出false。

总结:①当两个字符串没有通过new来创建的话,只要它们的值相同,那么它们进行相等运算(==)时返回true。

   ②当两个字符串都是使用new来创建的话,进行上述操作,都会返回false,因为它们不是同一个对象,也就不在同一个地址。示例代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class Test4 {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.           
  8.         String s2=new String("Java");  
  9.         String s3=new String("Java");  
  10.         System.out.println(s3==s2);//false  
  11.           
  12.     }  
  13.   
  14. }  

   ③当一个字符串使用new来创建,另外一个没有使用new来创建的话,进行上述操作,都会返回false,也是因为它们不是同一个对象。示例代码:见开篇时得代码,程序②处。


接下来不得不提到一个知识点:

String类中有一个intern方法,当调用这个方法时,虚拟机会查找常量池中是否有此字符串,如果查到,就返回常量池中的字符串,如果没有,就返回此字符串。示例代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class Test2 {  
  2.   
  3.     public static void main(String[] args) {  
  4.           
  5.         String s1="Hello Java";  
  6.         String s2="Hello Java";  
  7.         String s3=new String("Hello Java");  
  8.         //System.out.println(s1==s2);//①  
  9.         //System.out.println(s3==s2);//②  
  10.           
  11.         System.out.println(s1==s3.intern());//③  
  12.   
  13.     }  
  14.   
  15. }  
还是上面那个示例代码,只是最后一行有所改变,调用了s3的intern方法,此方法返回常量池中的Hello Java,所以程序③处放回true;

Interger类的常量池(-128--+127惹的祸)

废话不多说:直接上代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class Test5 {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         int i1=128;  
  8.         Integer i2=128;  
  9.         System.out.println(i1==i2);//①自动拆箱true  
  10.         Integer i3=128;  
  11.         System.out.println(i2==i3);//②常量池技术的体现。-128--+127false  
  12.         Integer i4=127;  
  13.         Integer i5=127;  
  14.         System.out.println(i4==i5);//③常量池技术的体现true  
  15.         Integer i6=new Integer(128);  
  16.         Integer i7=new Integer(128);  
  17.         System.out.println(i6==i7);//④两个不同的对象的体现。false  
  18.       
  19.   
  20.     }  
  21.   
  22. }  

程序①,④处很容易得到该结论,根据②的结论,③处也应该和②一样啊,但是为什么是true呢?这里涉及到常量池技术。

原来,在使用Integer   i  = 一个int型的数字的时候,会自动进行装箱操作,调用了integer类的valueof方法,通过网上搜索和查看源代码,会发现,此方法内部使用了一个缓冲技术,也就是常量池,但是此常量池只会对—128到+127之间的int型数字进行插入缓存的操作。当后续代码中出现类似前面的把一个int型数据赋值给Integer的时候,会直接从缓存里面将该值赋给变量。程序③处为127,小于128,所以会把i4存入常量池,当定义i5的时候,会把127赋值给i5,所以他们是同一个数,程序②处根据上面可知,他们会调用new来创建两个Integer对象。所以是false。

结论:①两个都是new出来的话,他们进行“==”操作时,一定返回false;

   ②一个是new出来的,一个是int型的,进行“==”操作,一定放回true,此时会进行拆箱。

   ③ 一个new出来的,另一个是将int赋值的,肯定返回false,因为此时不会拆箱操作。

   ④两个都是讲int型的赋值给Integer的话,如果int值介于-128到+127时,放回true,其它的返回false。


其它的使用到常量池技术的:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class Test6 {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.           
  8.         Long  l1=127l;  
  9.         Long  l2=127l;  
  10.         System.out.println(l1==l2);//①true  
  11.         Long  l3=128l;  
  12.         Long  l4=128l;  
  13.         System.out.println(l3==l4);//②false  Long型与Short型与Integer一样介于-128---+127之间  
  14.         Boolean   b1=false;  
  15.         Boolean   b2=false;  
  16.         System.out.println(b1==b2);//③true  Boolean实现了常量池技术  
  17.         Float f1=1.0f;  
  18.         Float f2=1.0f;  
  19.         System.out.println(f1==f2);//④false  Float与Double型没有实现常量池技术。  
  20.           
  21.   
  22.     }  
  23.   
  24. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值