在之前的文章我们介绍了一下 Java 中的Object,本章我们来看一下 Java 中的包装类。
在 Java 中有八个基本类型:byte,short,int,long,float,double,char,boolean,是以值的形式存在的,所以他们并没有面向对象的特征,自然也不继承自 Object,所以不能使用多台,用 Object 的角度去接受基本类型。
假设现在我们有一个计算 1+1 的值,代码如下:
1 public class Main { 2 public static void main(String[] args) { 3 int i = 1 + 1; 4 System.out.println(i); // 2 5 6 Integer integer1 = new Integer(1); 7 Integer integer2 = new Integer(1); 8 int integer = integer1.intValue() + integer2.intValue(); 9 System.out.println(integer); // 2 10 11 12 } 13 } 14 15 class Integer { 16 private int i; 17 18 public Integer(int i) { 19 this.i = i; 20 } 21 22 public int intValue() { 23 return i; 24 } 25 }
在上面的代码中,如果我们想要计算出 1+1 的值,按照之前所学的我们直接利用 int 类型数据 1+1 即可获取,但是我们在上面说了基本类型并不具备面向对象特征,那我们在某些情况下又需要怎么办呢,这就是上面代码中我们自己所写的 integer 类,但是如果我们仅仅是为了计算一个 1+1 ,每次都需要实例化一些 Integer 又太小题大做了。
所以 Java 就很贴心的为八个基本类型封装了一下,并且内置在了 lang 包内,即包装类,所以我们的代码如下也是可以正常运行的:
1 public class Main { 2 public static void main(String[] args) { 3 int i = 1 + 1; 4 System.out.println(i); // 2 5 6 Integer integer1 = new Integer(1); 7 Integer integer2 = new Integer(1); 8 int integer = integer1.intValue() + integer2.intValue(); 9 System.out.println(integer); // 2 10 } 11 }
包装类是不可变类,在构造了包装类对象后,不允许更改包装在其中的值,包装类是 final 的,不能定义他们的子类。
在上面的图片中,我们可以看出,数字类型的包装类继承自 Number,char 和 boolean 类型的包装类继承自 Object,接下来我们就举例看一下,如下代码:
1 /** 2 * 数字类型的包装类继承自 Number 3 * 其提供了入:intValue,doubleValue 这样的方法, 4 * 其作用是将当前包装类表示的数字以其他数字类型的形式返回 5 * */ 6 public class Main { 7 public static void main(String[] args) { 8 /** 9 * 将基本类型转换成包装类有两种方法: 10 * 1、调用构造方法 11 * 2、调用静态方法 valueOf(推荐) 12 * */ 13 Integer integer1 = new Integer(1); 14 Integer integer2 = new Integer(1); 15 System.out.println(integer1 == integer2); // false 16 System.out.println(integer1.equals(integer2)); // true 17 18 Integer integer3 = Integer.valueOf(1); 19 Integer integer4 = Integer.valueOf(1); 20 System.out.println(integer3 == integer4); // true 21 System.out.println(integer3.equals(integer4)); // true 22 23 Integer integer5 = Integer.valueOf(128); 24 Integer integer6 = Integer.valueOf(128); 25 System.out.println(integer5 == integer6); // false 26 System.out.println(integer5.equals(integer6)); // true 27 } 28 }
在上面的代码中,我们先使用实例化的方法,结果跟之前文章所讲的 equals 方法时所得的结果一样,当我们使用 valueOf() 方法时,发现 == 也变为了 true,这是因为 valueOf 会重用对象,并不会重新分配地址,但是仅限于 -128 -- 127 之间的整数。一旦超过会去 new 一个新对象。相比较而言,在 -128 -- 127 之间时,valueOf 会帮我们节省一部分内存空间,所以推荐使用 valueOf。
当然包装类也为我们提供了转为基本类型的方法,如下:
1 public class Main { 2 public static void main(String[] args) { 3 Integer integer = Integer.valueOf(128); 4 5 int int1 = integer.intValue(); 6 System.out.println(int1); // 128 7 8 float float1 = integer.floatValue(); 9 System.out.println(float1); // 128.0 10 11 // byte 类型为 -128 -- 127,超出会重新计算 12 byte byte1 = integer.byteValue(); 13 System.out.println(byte1); // -128 14 } 15 }
那我们怎么知道各个基本类型的最大值和最小值呢?包装类其实已经很贴心的为我们提供了方法,如下:
1 /** 2 * 数字类型包装类都支持两个常量 3 * MAX_VALUE , MIN_VALUE 4 * 分别保存了对应基本类型的最大值和最小值 5 * */ 6 public class Main { 7 public static void main(String[] args) { 8 int intMax = Integer.MAX_VALUE; 9 int intMin = Integer.MIN_VALUE; 10 System.out.println(intMax); // 2147483647 11 System.out.println(intMin); // -2147483648 12 13 byte byteMax = Byte.MAX_VALUE; 14 byte byteMin = Byte.MIN_VALUE; 15 System.out.println(byteMax); // 127 16 System.out.println(byteMin); // -128 17 } 18 }
通过上面的代码我们了解了包装类的一些基本特征和使用方法,那我们使用包装类的常用方法时什么呢?如下:
1 /** 2 * 包装类提供了一个静态方法 parseXXX(String str) 3 * 可以将给定的字符串转换为对应的基本类型 4 * 前提是该字符串必须正确的描述基本类型可以保存的值 5 */ 6 public class Main { 7 public static void main(String[] args) { 8 String str = "123"; 9 int i = Integer.parseInt(str); 10 System.out.println(i); // 123 11 12 double d = Double.parseDouble(str); 13 System.out.println(d); // 123.0 14 15 float f = Float.parseFloat(str); 16 System.out.println(f); // 123.0 17 18 String str1 = "123.123"; 19 int i1 = Integer.parseInt(str1); 20 System.out.println(i1); // 编译错误,Integer 并不能识别小数位 21 22 double d1 = Double.parseDouble(str1); 23 System.out.println(d1); // 123.123 24 } 25 }
在上面的代码中,我们分别定义了 "123" 和 "123.123" 两个字符串,从上面的输出结果可以看出,只有字符串能正确额描述基本类型可以保存的值才能运行成功。
接下来我们再来看一个包装类的自动拆装箱
1 /** 2 * JDK1.5 以后推出的新特性 3 * 自动拆装箱 4 */ 5 public class Main { 6 public static void main(String[] args) { 7 /** 8 * 自动拆装箱是编译器认可,而不是虚拟机认可 9 * 编译器在将源程序编译时自动补充代码来完成基本类型与包装类的转换 10 * */ 11 int i = new Integer(1); // 编译器会默认在后面加 .intValue() 12 Integer ii = 123; // 编译器会默认变为 Integer.valueOf(123) 13 } 14 }
在上面的代码中,我们可以看到 int 类型可以直接接受一个是实例化的包装类,包装类也可以直接接受一个基本类型的值,这就是自动拆装箱,避免了我们在编写程序时的转换,减少了代码量。