java基本数据类型对象包装类

java基本数据类型对象包装类

 

一、包装类说明

为了方便操作基本数据类型值,将其封装成了对象,在对象中定义了属性和行为丰富了该数据的操作。用于描述该对象的类就称为基本数据类型对象包装类。

基本数据类型相应的包装类

byte             Byte

short    Short

int         Integer

long             Long

float     Float

double Double

char             Character

boolean      Boolean

二、包装类主要功能

该包装对象主要用基本类型和字符串之间的转换。

(1)基本类型--->字符串

1、基本类型数值+""

2、用String类中的静态方法valueOf(基本类型数值);

3、用包装类的静态方法valueOf(基本类型数值);

(2)字符串--->基本类型

1、使用包装类中的静态方法:xxx parseXxx("xxx类型的字符串");

eg:

int parseInt("intstring");

long parseLong("longstring");

boolean parseBoolean("booleanstring");

备注:只有Character没有parse方法,本身就是封装了字符,无须转换

2、如果字符串被xxx包装类进行对象的封装。

可使用另一个非静态的方法,xxxValue();

将一个xxx包装类对象转成基本数据类型值。

三、JDK1.5自动装箱拆箱

(1)拆箱装箱概念

装箱:自动将基本数据类型转换为包装器类型;

拆箱:自动将包装器类型转换为基本数据类型。

(2)jdk1.5后包装类新特性


Integeri=4;//自动装箱,简化书写:Integer i=new Integer(4);
i=i+6;//i=new Integer(i.intValue+6);//自动拆箱
System.out.println(i.intValue());//10

(3)拆箱装箱实现

装箱:自动将基本数据类型转换为包装器类型;装箱过程是通过调用包装器的valueOf方法实现的

拆箱:自动将包装器类型转换为基本数据类型。拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。

【1】实现代码案例

package wrapper;


public class Autoboxing_Unboxing {


	public static void main(String[] args) {
	Integer i = 10;//装箱
        int n = i;//拆箱
	}
	
}

【2】反编译代码发现

反编译class文件之后得到如下内容:


 从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。

其他的也类似,比如Double、Character,不相信的朋友可以自己手动尝试一下。

 

【3】结论

  因此可以用一句话总结装箱和拆箱的实现过程:

装箱过程是通过调用包装器的valueOf方法实现的,

拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。

四、包装类装箱之valueOf方法之思

1、创建对象与valueOf方法【装箱】

思考:由于装箱过程是调用包装器的valueOf方法实现的,

即:当Integer i=3过程,创建Integer对象的时候,这样一个装箱过程,就会调用包装器的valueOf方法。所以,我们在此重点讨论这个valueOf方法。

2、valueOf方法结论

主要得出几个结论:

2.1不同包装类之间,有共性的地方。分为三大派别:

【1】Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。比较特殊,根据数值的大小范围而获得对象的方式不同

【2】Double、Float的valueOf方法的实现是类似的,每次都返回不同的对象。

【3】Boolean的valueOf方法实现,每次返回的都是同一个对象

2.2对于类别【1】

(1)有两种创建对象的情况:

《1》在一些特定取值范围内,创建的对象是共享的,即:该数值范围的对象,在内存中只创建一个(一次),以后想创建该数值的对象,直接获取即可,不需要去new新的。

这个范围的取值情况是:

相同对象范围:在该范围内,同数值情况下,对象是相同的,是同一个。

Integer    相同对象范围  [-128,127]

Short      相同对象范围  [-128,127] 

Byte      相同对象范围  [-128,127]  

Character  相同对象范围  [0,127]    

Long      相同对象范围 [-128,127]  

《2》除了上述的取值范围内,对象只创建一个,这里所说的范围内,对象不会共享,相同数值情况下,会创建不同的对象

这个范围的取值情况是:

不同对象范围:在该范围内,同数值情况下,对象是不同的,是多个不同的。

Integer    不同对象范围 i<128||i>=128

Short     不同对象范围 s<128||s>=128

Byte      不同对象范围  无

Character  不同对象范围  c>=128

Long      不同对象范围 L<128||L>=128

综合《1》《2》得

Integer    相同对象范围 [-128,127] 不同对象范围i<128||i>=128

Short     相同对象范围 [-128,127] 不同对象范围s<128||s>=128

Byte      相同对象范围 [-128,127] 不同对象范围

Character  相同对象范围 [0,127]   不同对象范围c>=128

Long     相同对象范围 [-128,127] 不同对象范围 L<128||L>=128

(2)Integer的valueOf源码

来源:CSDN博客

博文:Java 自动装箱和拆箱

博主:jackiehff

网址:http://blog.csdn.net/jackiehff/article/details/8509056

【1】valueOf工厂方法

   

 public static Integer valueOf(int i) {   
        if(i >= -128 &&i<=IntegerCache.high)   
          //如果i在-128~high之间,就直接在缓存中取出i的Integer类型对象 
          return IntegerCache.cache[i + 128];   
        else 
          return new Integer(i); //否则就在堆内存中创建  
    }   

【2】IntegerCache内部类

 private static class IntegerCache {//内部类,注意它的属性都是定义为static final 
        static final inthigh; //缓存上界 
        static final Integer cache[];//cache缓存是一个存放Integer类型的数组 
     
        static {//静态语句块 
           final int low = -128;//缓存下界,值不可变 
     
           // high valuemay beconfigured by property 
           int h = 127;// h值,可以通过设置jdk的AutoBoxCacheMax参数调整(参见(3)) 
           if (integerCacheHighPropValue!=null) { 
               // UseLong.decode here to avoid invoking methods that 
               // requireInteger's autoboxing cache to be initialized 
               // 通过解码integerCacheHighPropValue,而得到一个候选的上界值 
               int i = Long.decode(integerCacheHighPropValue).intValue(); 
               // 取较大的作为上界,但又不能大于Integer的边界MAX_VALUE 
               i = Math.max(i, 127);//上界最小为127 
               // Maximumarray size is Integer.MAX_VALUE 
               h = Math.min(i, Integer.MAX_VALUE - -low); 
           } 
           high = h; //上界确定,此时high默认一般是127 
           // 创建缓存块,注意缓存数组大小 
           cache =new Integer[(high - low) +1]; 
           int j = low; 
           for(int k = 0; k <cache.length; k++) 
               cache[k] =new Integer(j++);// -128到high值逐一分配到缓存数组 
       } 
     
        private IntegerCache() {}//构造方法,不需要构造什么 
    } 

分析:取值范围[-128,127]共享对象,之外创建独立对象

(3)Short的valueOf源码

  

public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 &&sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt +offset];
        }
        return new Short(s);
}

分析:取值范围[-128,127]共享对象,之外创建独立对象

 

(4)Long的valueOf源码

public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 &&l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
}

分析:取值范围[-128,127]共享对象,之外创建独立对象

(5)Byte的ValueOf源码

public static Byte valueOf(byte b) {
        final int offset = 128;
        return ByteCache.cache[(int)b +offset];
}
 
private static class ByteCache {
        private ByteCache(){}
        static final Byte cache[] =new Byte[-(-128) + 127 + 1];
        static {
            for(int i = 0; i < cache.length;i++)
                cache[i] =new Byte((byte)(i - 128));
        }
    }


分析:取值范围[-128,127]共享对象

备注:基本数据类型byte的取值范围[-128,127]

(6)Character的valueOf源码

  

 public static Character valueOf(char c) {
        if (c <= 127) {//must cache
            return CharacterCache.cache[(int)c];
        }
        return new Character(c);
}

分析:取值范围[0,127]共享对象,之外创建独立对象

(7)一些测试案例

《1》案例一

package wrapper;
 
public class CharacterTest {
 
    //测试结论: 0-127范围,对象共享;128开始,创建不同的新对象
    public static void main(String[] args) {
 
       Character c1=(char) 128;
       Character c2=(char)128;
       System.out.println(c1==c2);//false
       System.out.println(c1.equals(c2));//true
      
       Character c11=(char) 127;
       Character c12=(char)127;
       System.out.println(c11==c12);//true
       System.out.println(c11.equals(c12));//true
      
       Character c21=(char) 0;
       Character c22=(char)0;
       System.out.println(c21==c22);//true
       System.out.println(c21.equals(c22));//true
      
 
    }
 
}


《2》案例二

package wrapper;
 
public class ByteTest {
 
    //测试结论:byte取值的范围:-128-127
    //而在byte的范围内的对象都是可以共享的
   
    public static void main(String[] args) {
       //byte最大
       Byte b1=127;
       Byte b2=127;
       System.out.println(b1==b2);//true
       System.out.println(b1.equals(b2));//true
      
       //byte最小
       Byte b11=-128;
       Byte b12=-128;
       System.out.println(b11==b12);
       System.out.println(b11.equals(b12));
      
       //对于超出byte取值范围[-128,127]的,最终都会转为byte范围内的数字,所以一样得到了true的结果
      
//     Byte b12=128;//报错
       Byte b13=(byte) 128;
       //int(32位)的128强制类型转为byte(8位)型,其中会把多余的24位剔除,从而转换成byte范围的数
       Byte b23=(byte) 128;
       System.out.println(b13==b23);//true
       System.out.println(b13.equals(b23));//true
      
       Byte b21=(byte) -129;
       Byte b22=(byte) -129;
       System.out.println(b21==b22);//true
       System.out.println(b21.equals(b22));//true
      
    }
 
}


2.3对于类别【2】Double、Float的valueOf方法的实现是类似的,每次都返回不同的对象】

(1)Double 的ValueOf源码

   

 public static Double valueOf(double d) {
        returnnew Double(d);
}

分析:每次都创建不同的对象

(2)Float 的ValueOf源码

   

public static Float valueOf(floatf) {
        return new Float(f);
    }

分析:每次都创建不同的对象

 

2.4对于类别【3】Boolean的valueOf方法实现,每次返回的都是同一个对象

Boolean 的ValueOf源码

  

  public static final Boolean TRUE =new Boolean(true);
    public static final Boolean FALSE =new Boolean(false);
    public static Boolean valueOf(booleanb) {
        return (b ?TRUE : FALSE);
}

分析:每次的对象都是同一个,因为那个对象是创建好的常量。

五、包装类的equals方法

1、方法结论

1.1结论

equals方法为true时,需要满足两个条件:

1、类型相同  2、内容相同

1.2源码分析

(1)Integer的equals源码

  public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }


(2)Short的equals源码

 

 public boolean equals(Object obj) {
        if (obj instanceof Short) {
            return value == ((Short)obj).shortValue();
        }
        return false;
    }

(3)Long的equals源码

  

public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }

(4)Character的equals源码

  public boolean equals(Object obj) {
        if (obj instanceof Character) {
            return value == ((Character)obj).charValue();
        }
        return false;
    }


(5)Byte的equals源码

 

 public boolean equals(Object obj) {
        if (obj instanceof Byte) {
            return value == ((Byte)obj).byteValue();
        }
        return false;
    }

(6)Float的equals源码

  

  public boolean equals(Objectobj) {
        return (obj instanceof Float)
               && (floatToIntBits(((Float)obj).value) ==floatToIntBits(value));
    }

(7)Double的equals源码

 

   public boolean equals(Objectobj) {
        return (obj instanceof Double)
               && (doubleToLongBits(((Double)obj).value) ==
                      doubleToLongBits(value));
    }

(8)Boolean的equals源码

  

  public boolean equals(Objectobj) {
        if (obj instanceof Boolean) {
            returnvalue == ((Boolean)obj).booleanValue();
        }
        return false;
    }

六、包装类一些结论总结

1、当一个基础数据类型封装类进行==运算时,会将封装类进行拆箱

2、+运算时,会将封装类进行拆箱

3、当封装类与基础类型进行==运行时,封装类会进行拆箱,拆箱结果与基础类型对比值;

两个封装类进行==运行时,与其它的对象进行==运行一样,对比两个对象的地址,也即判断是否两个引用是否指向同一个对象。

4、陷阱一:有拆箱操作时一定要特别注意封装类对象是否为null,如果为空,则不能调用对象的任何方法,否则会报错

5、陷阱二:不同范围数值的对象产生情况不同(详情看:四、包装类装箱之valueOf方法之思)

该结论来自以下参考文章,如果想了解详细,请看该文

博文:详解Java的自动装箱与拆箱(Autoboxingand unboxing)

博主:Mirhunana

网址:http://blog.csdn.net/hp910315/article/details/48654777

七、包装类综合实例应用

package wrapper;
 
public class Test {
 
    public static void main(String[] args) {
       /*
        * 当 "=="运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,
        * 而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。
        * 另外,对于包装器类型,equals方法并不会进行类型转换
        */
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;//大于一个字节表示范围(byte:-128-127)
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;
 
 
        //如果装箱的是一个字节,该数据会被共享不会重新开辟空间
        System.out.println(c==d);//true
        System.out.println(e==f);//false 
       
        /*
         * a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),
         * 因此它们比较的是数值是否相等。
         * 
         * 而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,
         * 也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,
         * 便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,
         * 不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,
         * 装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)
         */
       
        /*
         * 3=(1+2)
         * a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),
         * 因此它们比较的是数值是否相等。
         */
        System.out.println(c==(a+b));//true
       
        /*
         * 3.equals(1+2)
         * 先自动拆箱,左边数值为3,右边数值为3;
         * 然后出发自动装箱,装箱过程中调用Integer.valueOf方法,
         * 即:如果装箱的是一个字节,该数据会被共享不会重新开辟空间
         * 过左边和右边是同一个空间的地址,所以相等
         */
        System.out.println(c.equals(a+b));//true
       
//       System.out.println("3L==(1+2)--"+(3L==(1+2)));
       
        /*
         * 3L==(1+2)
         * a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),
         * 因此它们比较的是数值是否相等。
         * 左边为3L 右边为3 ,两者的值相等吗?
         * 相等:int与 long进行运算、比较时 int 会自动进行类型提升为 long类型
         *      类型自动提升
         */
        System.out.println(g==(a+b));//true
        /*
         * 3L.equals(1+2)
         * 先自动拆箱,左边数值为3L,右边数值为3;
         * 然后出发自动装箱,装箱过程中左边调用Double.valueOf方法,右边调用Integer.valueOf方法
         * 左边为Long型,右边为Integer型(原因:类型不同,内容相同)
         */
        System.out.println(g.equals(a+b));//false
 
        /*
         * 3L.equals(1+2L)
         * 先自动拆箱,左边数值为3L,右边数值为3L(运算的时候,由于自动类型转换,所以为3L);
         * 然后出发自动装箱,装箱过程中两边都调用Double.valueOf方法
         * 两边数值相等,故相等(类型和内容相同)
         */
        System.out.println(g.equals(a+h));//true
    }
 
}

八、参考文章

1、参考文章一

来源:CSDN博客

博文:Java 自动装箱和拆箱

博主:jackiehff

网址:http://blog.csdn.net/jackiehff/article/details/8509056

2、参考文章二

来源:博客园

博文:深入剖析Java中的装箱和拆箱

博主:海 子

网址:http://www.cnblogs.com/dolphin0520/p/3780005.html

3、参考文章三

来源:CSDN博客

博文:Java自动装箱与拆箱及其陷阱

博主:JairusChan

网址:http://blog.csdn.net/jairuschan/article/details/7513045

4、参考文章四

来源:CSDN博客

博文:详解Java的自动装箱与拆箱(Autoboxing and unboxing)

博主:Mirhunana

网址:http://blog.csdn.net/hp910315/article/details/48654777

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值