java包装类

转自:http://macemers.iteye.com/blog/860631

定义:Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)

Java包装类,Wrapper~由于在java中,数据类型总共可分为两大种,基本数据类型(值类型)和类类型(引用数据类型)。基本类型的数据不是对象,所以对于要将数据类型作为对象来使用的情况,java提供了相对应的包装类

java数据类型图:
                                             ┏数值型━┳━整数型:byte short int long
              ┏基本数据类型━━┫              ┗━浮点型:float double
              ┃                            ┣字符型:char                                          
数据类型╋                            ┗布尔型:boolean              
              ┃                            ┏类(class)
              ┗引用数据类型━━╋接口(interface)
                                             ┗数组(array)
1.基本八大类,图中可以很清楚的看到;这种类型的数据变量在声明之后java就会立刻分配给他内存空间。如:short a;  java会在可使用的内存空间寻找一个占两个字节的块给a变量;
2.引用数据类型就那三种,类似C/C++的指针,它以特殊的方式指向对象实体(具体的值),这类变量声明时不会分配内存,只是存储了一个内存地址,想具体知道看看数据结构就好了
基本数据类型和引用数据类型的区别:

基本数据类型在被创建时,在栈上给其划分一块内存,将数值直接存储在栈上;

引用数据类型在被创建时,首先要在栈上给其引用(句柄)分配一块内存,而对象的具体信息都存储在堆内存上,然后由栈上面的引用指向堆中对象的地址。

对于8种数据类型的包装类分别是: 
int---Integer 
char---Character 
float---Float 
double---Double 
byte---Byte 
short---Short 
long---Long 
boolean--Boolean 

包装类提供了很多互相转换的方法,这里不一一细说,这里关注的是包装类的装箱和拆箱问题。 

所谓装箱,就是把基本类型用它们相对应的引用类型包起来,使它们可以具有对象的特质,如我们可以把int型包装成Integer类的对象,或者把double包装成Double,等等。 

所谓拆箱,就是跟装箱的方向相反,将Integer及Double这样的引用类型的对象重新简化为值类型的数据 

J2SE5.0后提供了自动装箱与拆箱的功能,此功能事实上是编译器来帮您的忙,编译器在编译时期依您所编写的方法,决定是否进行装箱或拆箱动作。 

自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中。 

自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动地提取出来,没必要再去调用intValue()和doubleValue()方法。 

自动装箱,只需将该值赋给一个类型包装器引用,java会自动创建一个对象。例如:
Java代码   收藏代码
  1. Integer i=100;//没有通过使用new来显示建立,java自动完成。  


自动拆箱,只需将该对象值赋给一个基本类型即可。例如:int j=i; 
Java代码   收藏代码
  1. int i = 10;  
  2. Integer j =new Integer(i); //手动装箱操作    
  3. int k = j.intValue();      //手动拆箱操作    
  4.   
  5. int i = 11;  
  6. Integer j = i; //自动装箱  
  7. int k = j //自动拆箱  


然而在Integer的自动装拆箱会有些细节值得注意: 
Java代码   收藏代码
  1. public static void main(String[] args) {  
  2.     Integer a=100;  
  3.         Integer b=100;  
  4.           
  5.         Integer c=200;  
  6.         Integer d=200;  
  7.           
  8.         System.out.println(a==b);   //1  
  9.         System.out.println(a==100); //2  
  10.           
  11.         System.out.println(c==d);   //3  
  12.         System.out.println(c==200); //4  
  13.    }  

在java种,"=="是比较object的reference而不是value,自动装箱后,abcd都是Integer这个Oject,因此“==”比较的是其引用。按照常规思维,1和3都应该输出false。但结果是: 
true 
true 
false 
true 

结果2和4,是因为ac进行了自动拆箱,因此其比较是基本数据类型的比较,就跟int比较时一样的,“==”在这里比较的是它们的值,而不是引用。 

对于结果1,虽然比较的时候,还是比较对象的reference,但是自动装箱时,java在编译的时候 Integer a = 100; 被翻译成-> Integer a = Integer.valueOf(100); 
关键就在于这个valueOf()的方法。 
Java代码   收藏代码
  1. public static Integer valueOf(int i) {     
  2. final int offset = 128;     
  3. if (i >= -128 && i <= 127) { // must cache     
  4. return IntegerCache.cache[i + offset];     
  5. }     
  6. return new Integer(i);     
  7. }     


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

根据上面的jdk源码,java为了提高效率,IntegerCache类中有一个数组缓存了值从-128到127的Integer对象。当我们调用Integer.valueOf(int i)的时候,如果i的值是>=-128且<=127时,会直接从这个缓存中返回一个对象,否则就new一个Integer对象。  
具体如下: 
Java代码   收藏代码
  1. static final Integer cache[] = new Integer[-(-128) + 127 + 1]; //将cache[]变成静态  
  2. static {  
  3.         for(int i = 0; i < cache.length; i++)  
  4.         cache[i] = new Integer(i - 128); //初始化cache[i]  
  5.     }  


这是用一个for循环对数组cache赋值,cache[255] = new Integer(255-128),也就是newl一个Integer(127) ,并把引用赋值给cache[255],好了,然后是Integer b= 127,流程基本一样,最后又到了cache[255] = new Integer(255-128),这一句,那我们迷糊了,这不是又new了一个对象127吗,然后把引用赋值给cache[255],我们比较这两个引用(前面声明a的时候也有一个),由于是不同的地址,所以肯定不会相等,应该返回false啊!呵呵,这么想你就错了,请注意看for语句给cache[i]初始化的时候外面还一个{}呢,{}前面一个大大的static关键字,是静态的,那么我们就可以回想下static有什么特性了,只能初始化一次,在对象间共享,也就是不同的对象共享同一个static数据。 

那么当我们Integer b = 127的时候,并没有new出一个新对象来,而是共享了a这个对象的引用,记住,他们共享了同一个引用!!!,那么我们进行比较a==b时,由于是同一个对象的引用(她们在堆中的地址相同),那当然返回true了!!! 

知道了为什么,我们就来看看下面的代码: 
Java代码   收藏代码
  1. public class Test {  
  2.         public static void main(String args[]){  
  3.                 Integer m = new Integer(5);  
  4.                 Integer n = new Integer(5);  
  5.                 System.out.println(m==n);  
  6.                 m = m-1;  
  7.                 n = n-1;  
  8.                 System.out.println(m==n);  
  9.         }  
  10. }  

输出什么? 
false 
true 
原因: 
m,n因为都是new出来的对象,内存地址不一样,所以第一次m==n比较的reference不一样。(但是,m=m-1首先进行了自动拆箱m.intValue,相减后再进行装箱动作:m=Integer.valueOf(m.intValue-1),而m和n都在 -128--127的范围,所以自动装箱后,根据上文所述,都是同一个object的引用。因此第二次输出true。 )感觉括号中的内容是直接比较两个数值,不是比较两个对象引用地址。(其实还是比较两个对象,参见改善java程序151个建议第28个建议)

注意下边两种方法的区别:

Integer b = 127的时候,并没有new出一个新对象来,而是共享了a这个对象的引用:

  1.  Integer a=100;  
  2.         Integer b=100;  
  1.  Integer m = new Integer(5);  
  2.                 Integer n = new Integer(5);  
使用new必然是一个新的对象:

类似于String a=“test”;  和String b=new String("test1");   第一种情况先去字符串常量池中寻找是否有这个值,没有的话再new一个。

如果有直接让饮用变量a指向字符串常量池中的这个对象。        第二种是new一个新对象。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值