Java包装类、装箱拆箱

来源:互联网 发布:java se技术文档 编辑:程序博客网 时间:2024/04/27 21:49

基本类型 – -包装类
boolean — Boolean
byte ——— Byte(8)
char ———-Character
short ———Short
int ————Integer
long ———-Long(4)
float ———-Float
double——–Double


● 将String转换成包装类:
每个包装类都有一个静态的valueOf()方法
valueOf()方法:

String str = "120";    Byte obj_Byte = Byte.valueOf(str);    Integer obj_Int = Integer.valueOf(str);    Long obj_Long = Long.valueOf(str);    Short obj_Short = Short.valueOf(str);    Float obj_Float = Float.valueOf(str);    System.out.println(obj_Byte + obj_Int + str + obj_Long + obj_Short + obj_Float);

输出结果是:240120120120120.0
若输出:System.out.println(obj_Byte + obj_Int + str + obj_Long + obj_Float+ obj_Short );

结果:240120120120.0120

● 将包装类转化成基本类型:
除了Boolean和Character类以外,其他包装类都有静态的parse 方法。
.parseXXX()方法:

byte obj_byte = Byte.parseByte(str);short obj_short = Short.parseShort(str);int obj_int = Integer.parseInt(str);long obj_long = Long.parseLong(str);float obj_float = Float.parseFloat(str);System.out.println(obj_byte + obj_short + obj_int + obj_float + obj_long);

输出结果:600.0


● Character类

包含的方法:
1. isDigit() 是不是数字
2. isLetter() 是不是字母
3. isWhitespace() 是不是空格
4. isUpperCase() 是不是大写
5. isLowerCase() 是不是小写

char[] charArray = { '*', ' ', '1', 'a', 'A' };for (int i = 0; i < charArray.length; i++) {        if (Character.isDigit(charArray[i])) {            System.out.println(charArray[i] + "是一个数字");        }        if (Character.isLetter(charArray[i])) {            System.out.println(charArray[i] + "是一个字母");        }        if (Character.isWhitespace(charArray[i])) {            System.out.println(charArray[i] + "是一个空格");        }        if (Character.isUpperCase(charArray[i])) {            System.out.println(charArray[i] + "是一个大写字母");        }        if (Character.isLowerCase(charArray[i])) {            System.out.println(charArray[i] + "是一个小写字母");        }    }

● 拆箱装箱

直接将一个基础数据类型传给其相应的封装类(wrapper class)的做法,便是自动装箱(Autoboxing)。
integer100为一个Integer类型的引用,int100为一个int类型的原始数据类型。但是,我们可以将一个Integer类型的对象赋值给其相应原始数据类型的变量。这便是拆箱。
装箱是将一个原始数据类型赋值给相应封装类的变量。而拆箱则是将一个封装类的变量赋值给相应原始数据类型的变量。

int x = 1;Integer y = x;          // 装箱int z = y;              // 拆箱System.out.println("y="+y+"\tz="+z);

● 扩展:

● 实验一:

  Integer integer400=400;    int int400=400;    System.out.println(integer400==int400);  

在以上代码的第三行中,integer400与int400执行了==运行。而这两个是不同类型的变量,到底是integer400拆箱了,还是int400装箱了呢?运行结果是什么呢?
==运算是判断两个对象的地址是否相等或者判断两个基础数据类型的值是否相等。所以,大家很容易推测到,如果integer400拆箱了,则说明对比的是两个基础类型的值,那此时必然相等,运行结果为true;如果int400装箱了,则说明对比的是两个对象的地址是否相等,那此时地址必然不相等,运行结果为false。(至于为什么笔者对它们赋值为400,就是后面将要讲到的陷阱有关)。
我们实际的运行结果为true。所以在用 == 时,是integer400拆箱了。

● 实验二:

● Integer integer100=100;
● int int100=100;
● System.out.println(integer100.equals(int100));

在以上代码的第三行中,integer100的方法equals的参数为int100。我们知道equals方法的参数为Object,而不是基础数据类型,因而在这里必然是int100装箱了。对代码跟踪的结果也证明了这一点。
其实,如果一个方法中参数类型为原始数据类型,所传入的参数类型为其封装类,则会自动对其进行拆箱;相应地,如果一个方法中参数类型为封装类型,所传入的参数类型为其原始数据类型,则会自动对其进行装箱。
实际运行结果是:true。所以在用equals时,int100进行了装箱。

● 实验三:

Integer integer100 = 100;  int int100 = 100;  Long long200 = 200l;  System.out.println(integer100 + int100);  System.out.println(long200 == (integer100 + int100));  System.out.println(long200.equals(integer100 + int100));  

在第一个实验中,我们已经得知,当一个基础数据类型与封装类进行==运算时,会将封装类进行拆箱。那如果+、-、*、/呢?我们在这个实验中,就可知道。
如果+运算,会将基础数据类型装箱,那么:
● 第4行中,integer100+int100就会得到一个类型为Integer且value为200的对象o,并执行这个对象的toString()方法,并输出”200”;
● 第5行中,integer100+int100就会得到一个类型为Integer且value为200的对象o,==运算将这个对象与long200对象进行对比,显然,将会输出false;
● 第6行中,integer100+int100就会得到一个类型为Integer且value为200的对象o,Long的equals方法将long200与o对比,因为两都是不同类型的封装类,因而输出false;
如果+运算,会将封装类进行拆箱,那么:
● 第4行中,integer100+int100就会得到一个类型为int且value为200的基础数据类型b,再将b进行装箱得到o,执行这个对象的toString()方法,并输出”200”;
● 第5行中,integer100+int100就会得到一个类型为int且value为200的基础数据类型b1,==运算将long200进行拆箱得到b2,显然b1==b2,输出true;
● 第6行中,integer100+int100就会得到一个类型为int且value为200的基础数据类型b,Long的equals方法将b进行装箱,但装箱所得到的是类型为Integer的对象o,因为o与long200为不同的类型的对象,所以输出false;
程序运行的结果为:
1. 200
2. true
3. false
因而,第二种推测是正确,即在+运算时,会将封装类进行拆箱。

● 陷阱:

● 陷阱一:

Integer integer100=null;  int int100=integer100;  

这两行代码是完全合法的,完全能够通过编译的,但是在运行时,就会抛出空指针异常。其中,integer100为Integer类型的对象,它当然可以指向null。但在第二行时,就会对integer100进行拆箱,也就是对一个null对象执行intValue()方法,当然会抛出空指针异常。所以,有拆箱操作时一定要特别注意封装类对象是否为null。

● 陷阱二:

Integer i1=100;  Integer i2=100;  Integer i3=300;  Integer i4=300;  System.out.println(i1==i2);  System.out.println(i3==i4);

因为i1、i2、i3、i4都是Integer类型的,所以我们想,运行结果应该都是false。但是,真实的运行结果为“System.out.println(i1==i2);”为 true,但是“System.out.println(i3==i4);”为false。也就意味着,i1与i2这两个Integer类型的引用指向了同一个对象,而i3与i4指向了不同的对象。为什么呢?不都是调用Integer.valueOf(int i)方法吗?

让我们再看看Integer.valueOf(int i)方法。

/** * Returns a <tt>Integer</tt> instance representing the specified * <tt>int</tt> value. * If a new <tt>Integer</tt> instance is not required, this method * should generally be used in preference to the constructor * {@link #Integer(int)}, as this method is likely to yield * significantly better space and time performance by caching * frequently requested values. * * @param  i an <code>int</code> value. * @return a <tt>Integer</tt> instance representing <tt>i</tt>. * @since  1.5 */  public static Integer valueOf(int i) {    if(i >= -128 && i <= IntegerCache.high)          return IntegerCache.cache[i + 128];      else        return new Integer(i);    }  

我们可以看到当i>=-128且i<=IntegerCache.high时,直接返回IntegerCache.cache[i + 128]。其中,IntegerCache为Integer的内部静态类,其原码如下:

 private static class IntegerCache {           static final int high;            static final Integer cache[];           static {               final int low = -128;               // high value may be configured by property               int h = 127;               if (integerCacheHighPropValue != null) {                  // Use Long.decode here to avoid invoking methods that                   // require Integer's autoboxing cache to be initialized                   int i = Long.decode(integerCacheHighPropValue).intValue();                    i = Math.max(i, 127);                    // Maximum array size is Integer.MAX_VALUE                     h = Math.min(i, Integer.MAX_VALUE - -low);                }                 high = h;                 cache = new Integer[(high - low) + 1];                 int j = low;                 for(int k = 0; k < cache.length; k++)                     cache[k] = new Integer(j++);             }             private IntegerCache() {}         }  

我们可以清楚地看到,IntegerCache有静态成员变量cache,为一个拥有256个元素的数组。在IntegerCache中也对cache进行了初始化,即第i个元素是值为i-128的Integer对象。而-128至127是最常用的Integer对象,这样的做法也在很大程度上提高了性能。也正因为如此,“Integeri1=100;Integer i2=100;”,i1与i2得到是相同的对象。
对比扩展中的第二个实验,我们得知,当封装类与基础类型进行==运行时,封装类会进行拆箱,拆箱结果与基础类型对比值;而两个封装类进行==运行时,与其它的对象进行==运行一样,对比两个对象的地址,也即判断是否两个引用是否指向同一个对象。

0 0
原创粉丝点击