首先说一下Java中的包装类,Java语言是一个面向对象的语言,但是Java中的基本数据类型却不是面向对象的,这在实际使用时存在很多的不便(比如,我们不能直接想集合Collections中放入原始类型值,因为集合只接收对象)。为了解决这个不足,在设计类的是为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
基本数据类型 |
包装类 |
byte |
Byte |
boolean |
Boolean |
short |
Short |
char |
Character |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
自动装箱就是Java自动将原始类型转化为对应的对象,比如将int的变量转化为Integer对象,这个过程叫做装箱,反之将Integer对象转化为int对象,这个过程叫做拆箱。又因为这个过程是自动发生的,所以又叫自动装箱,自动拆箱。
ArrayList<Integer> arrayList = new ArrayList<Integer>(); arrayList.add(1); //自动装箱 int --> Integer int number = arrayList.get(0); //自动拆箱 Integer --> int
简单点说,装箱就是自动将基本类型转化为包装类型,拆箱就是自动将包装类型转化为基本类型。
在自动装箱的过程中,系统为我们执行了
Integer total = Integer.valueOf(1);
自动拆箱的过程中,系统为我们执行了
int number = total.intValue();
弊端:
有些情况中,自动装箱如果不注意的话会创建多余的对象,影响程序的性能。
Integer sum = 0; for(int i=1000; i<5000; i++){ sum+=i; }
上述代码中 sum+=i 可以看成 sum = sum +i,但是这个 + 操作符不适用与Integer对象,首先sum进行自动拆箱操作,进行数值的相加操作,最后发生自动装箱操作转化为Integer对象。
其内部的变化如下:
sum = sum.intValue() + i; Integer sum = new Integer(result);
由于我们声明的sum为Integer类型,在上面的循环中会创建将近4000个无用的对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。因此在我们编程时,需要注意到这一点,正确的声明变量类型,避免因为自动装箱引起的性能问题。
在Integer类内部包含了一些和int操作有关的方法,下面介绍一些比较常用的方法:
a、parseInt方法
public static int parseInt(String s)
该方法的作用是将数字字符串转换为int数值。在以后的界面编程中,将字符串转换为对应的int数字是一种比较常见的操作。使用示例如下:
String s = “123”;
int n = Integer.parseInt(s);
则int变量n的值是123,该方法实际上实现了字符串和int之间的转换,如果字符串都包含的不是都是数字字符,则程序执行将出现异常。
另外一个parseInt方法:
public static int parseInt(String s, int radix)
则实现将字符串按照参数radix指定的进制转换为int,使用示例如下:
//将字符串”120”按照十进制转换为int,则结果为120
int n = Integer.parseInt(“120”,10);
//将字符串”12”按照十六进制转换为int,则结果为18
int n = Integer.parseInt(“12”,16);
//将字符串”ff”按照十六进制转换为int,则结果为255
int n = Integer.parseInt(“ff”,16);
这样可以实现更灵活的转换。
b、toString方法
public static String toString(int i)
该方法的作用是将int类型转换为对应的String类型。
使用示例代码如下:
int m = 1000;
String s = Integer.toString(m);
则字符串s的值是”1000”。
另外一个toString方法则实现将int值转换为特定进制的字符串:
public static int parseInt(String s, int radix)
使用示例代码如下:
int m = 20;
String s = Integer.toString(m);
则字符串s的值是”14”。
另外说一个前两天遇到的问题
int i = Integer.valueOf("222"); System.out.println(i);
在用findbugs查到了这个问题,进行了多余的拆箱和装箱操作,原因是 Interger.valuesOf("")返回的是 Integer对象,然后再拆箱到 int类型。
看几个例子
int i = 128; Integer i2 = 128; Integer i3 = new Integer(128); //Integer会自动拆箱为int,所以为true System.out.println(i == i2); //true System.out.println(i == i3); //true System.out.println("**************"); System.out.println(i2 == i3); //false Integer i5 = 127;//java在编译的时候,被翻译成-> Integer i5 = Integer.valueOf(127); Integer i6 = 127; System.out.println(i5 == i6);//true /*Integer i5 = 128; Integer i6 = 128; System.out.println(i5 == i6);//false */ Integer ii5 = new Integer(127); System.out.println(i5 == ii5); //false Integer i7 = new Integer(127); Integer i8 = new Integer(123); System.out.println(i7 == i8); //false
总结一下就是如果 Integer 和int类型相比,那么会将Integer类型拆箱为int类型的然后进行数值比较,如果是 Integer i = new Integer (127);这种会创建新的 Integer对象,所以实际对比的是两个对象,基本会返回false(当然如果和int类型相比也是返回 数值比较结果)。如果 是 Integer i1 = 127,Integer i2 = 127,这种比较的话,如果小于128 会返回true,大于等于128 会返回false。
为什么会出现这样呢,上面说到 integer i = 127, 会执行装箱操作,实际上 是执行了 Integer.valueOf(127),我们看一下 valueOf函数
public static Integer valueOf(int i) { return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128]; }
它会首先判断i的大小:如果i小于-128或者大于等于128,就创建一个Integer对象,否则执行SMALL_VALUES[i + 128]。
private static final Integer[] SMALL_VALUES = new Integer[256];
它们的值在(-128,128]这个范围内,它们会拿到SMALL_VALUES数组里面的同一个对象SMALL_VALUES[228],它们引用到了同一个Integer对象。