一、什么是包装类?
Java 中的包装类是用于将基本数据类型(如 int、char、boolean 等)包装成对象的类。每种基本数据类型都有对应的包装类,这些包装类提供了一种面向对象的方式来处理基本数据类型,允许它们被用于需要对象的场景,如集合框架、泛型等。
二、基本数据类型对应的包装类
基本数据类型 | 对应的包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
包装类型出现的原因:
因为Java是一个面向对象的语言,基本类型并不具有对象的性质,为了与其他对象“接轨”就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
常用的操作:用于基本数据类型与字符串之间的转换
public class IntegerTest {
public static void main(String[] args) {
//Integer(int value);构造一个新分配的Integer对象,它表示指定的int值
// Integer(String s)// 构造一个新分配的Integer对象,它表示 String 参数所指示的int值R\
Integer int1 = new Integer(123);
Integer int2 = new Integer("123");
System.out.println(int1);
System.out.println(int2);
//两者的结果输出都是123,这就是两个构造方法的使用
}
}
如果用String和int类型相互转换,当然这就需要用到Integer的一些方法
int→String:
public class IntegerTest {
public static void main(String[] args) {
//使用int和String相互转换
// int----String有两个方法 ①直接拼接 ②使用valueOf(int i) 方法
int i = 10;
// ①直接拼接
String s1 = ""+i;
System.out.println(s1); //简单方便
// ②使用valueOf(int i) 方法
String s2 = String.valueOf(i);
System.out.println(s2);
}
}
String→int:
public class IntegerTest1 {
public static void main(String[] args) {
//方法一:
// String---->Integer----->int
// 先将String转为Integer包装类,然后使用Integer内的方法intValue() 返回int
String s ="100";
Integer i = Integer.valueOf(s);
i.intValue();
//Integer内的方法intValue() 返回int
System.out.println(i);
//方法二:
// Integer方法: parseInt(String s) ,将字符串参数作为带符号的十进制整数
int y = Integer.parseInt(s);
System.out.println(s);
}
}
Integer的equals方法:
Integer的equals方法继承自Object,并且进行了重写,也就是判断两个Integer值是否相等
public class IntegerTest2 {
public static void main(String[] args) {
Integer i1 = new Integer(123); //输入int型的123
Integer i2 = new Integer("123"); //输入String型的123
boolean b = i1.equals(i2); //判断两个Integer值是否相等
System.out.println(b);//这里输出的数true
// Integer类型的对象 i1 和 i2包含的值相等时;其他情况返回false
}
}
Integer的其他主要方法,红色字体便是方法名:
方法名 | 作用 |
static integer decode(String nm) | 将String转成Integer |
static int compare(int x, int y) | 比较两个数是否相等;相等返回0;前大后小返回1;后大前小返回-1 |
static int signum(int i) | 符号的数;负数返回-1;正数返回1;0返回0 |
static String toBinaryString(int i) | 将i转成二进制 |
static String toHexString(int i) | 将i转成十六进制 |
static String toOctalString(int i ) | 将i转成八进制 |
常用方法 | 作用 |
static int parselnt(String s) | 字符串转int |
static Integer valueOf(String s) | 字符串转Integer |
String tostring( ) | Integer转String |
boolean equals(Object obj) | 判断两个Integer是否相等 |
三、基本类型和包装类型的特点
-
基本类型的优势:数据存储相对简单,运算效率比较高
-
包装类的优势:有的容易,比如集合的元素必须是对象类型,满足了java一切皆是对象的思想
-
声明方式不同:基本类型不适用new关键字,而包装类型需要使用new关键字来在堆中分配存储空间
-
存储方式及位置不同:基本类型是直接将变量值存储在堆栈中,而包装类型是将对象放在堆中,然后通过引用来使用;
-
初始值不同:基本类型的初始值如int为0,boolean为false,而包装类型的初始值为null
-
使用方式不同,基本类型直接赋值直接使用就可以
包装类特点:
封装性:所有的包装类都是 final 类,这意味着它们不能被继承。这种设计确保了包装类的行为和特性的一致性,从而避免了子类可能引入的不确定性。
不可变性:包装类的实例一旦被创建后,其中保存的基本数据类型数据就不能再被改变。这种不可变性使得包装类在多线程环境中更加安全,避免了因数据被意外修改而导致的错误。
提供方法:包装类封装了许多实用的方法,提供了丰富的功能。例如,它们支持数据类型转换、判断字符串的大小写、以及获取最大值和最小值等。
继承关系:除了 Character 和 Boolean 之外,其他所有的包装类都继承自 Number 类。这种继承关系使得这些包装类能够共享一些通用的功能和特性,例如数字的比较和转换,这为在不同数值类型之间的操作提供了一致的接口。
包装类用途:
对象操作:在Java中,许多集合类和框架方法需要对象作为参数,而不是基本数据类型。为了满足这一需求,包装类提供了将基本数据类型转换为对象的机制。通过使用包装类,我们可以轻松地在这些方法中传递基本数据类型。
Null值处理:基本数据类型无法为null,而包装类则可以。这一特性在某些情况下非常有用,例如在方法参数中,需要表示可选值或缺省值时。通过使用包装类,我们能够更灵活地处理这些场景,确保代码的健壮性和可读性。这种设计使得我们在处理数据时,可以更方便地进行null值检查,并在需要时安全地进行区分,从而提高了代码的灵活性。
四、装箱和拆箱
Java 5引入了自动装箱(Auto-boxing)和自动拆箱(Auto-unboxing)机制,简化了基本数据类型与包装类之间的转换过程。
1.装箱
定义:装箱(Boxing)是将基本数据类型转换为相应的包装类的过程。
public class BoxingTest {
public static void main(String[] args) {
//装箱
//这是一个Integer普通的构造:
Integer i1=new Integer(100); // 手动装箱方式一
//而这个写法就是自动装箱,其实这个底层也做了new Integer(100)
Integer i2 =100;//这两者效果是一样的
Integer i3 = i2.intValue();// 手动装箱方式二
System.out.println(i1);
System.out.println(i3);
}
}
2.拆箱
定义:拆箱(Unboxing)是将包装类转换为基本数据类型的过程。
public class UnBoxingTest {
public static void main(String[] args) {
//比如要给i1加上200
Integer i1= 100;
//因为现在i1是引用数据类型,得先转换成基本数据类型
i1 = i1.intValue()+200;//这个叫手动拆箱
System.out.println(i1);//这样输出就是300
// 自动拆箱:
Integer i2 = 100;
i2+=200; //这个就是自动拆箱,
//其实这个自动拆箱底层完成了一次拆箱和一次装箱
//首先i2.intValue(), 然后i2 = i2+200
System.out.println(i2);
}
}
注意:但是我们会发现一个小问题:只要是对象,在操作前,必须做一个不为null的判断。
public class Test {
public static void main(String[] args) {
//当i为null的时候:
Integer i = null;
//i+=100;
//System.out.println(i);
//这样执行会报一个NullPointerException的错误
//所以我们需要添加一个判断:
if(i != null){
i+=100;
}
System.out.println(i);
}
}
实际上,包装类比基本类型更好用——基本类型能做的事情,包装类也能做。 但包装类能做的,基本类型不一定能做,比如要赋一个 null 值。
3.底层实现
(1)自动装箱的底层实现
自动装箱是通过调用包装类的valueOf()方法来实现的。
我们可以通过调试来验证这一结论,在要发生自动装箱的地方打上断点,然后直接跳到这个断点处,然后强制进入(force step into),就会进入到 valueOf() 方法中。
(2)自动拆箱的底层实现
自动拆箱是通过调用包装类对象的xxxValue()方法来实现的。
我们可以通过调试来验证这一结论,在要发生自动拆箱的地方打上断点,然后直接跳到这个断点处,然后强制进入(force step into),就会进入到 xxxValue() 方法中。