第十一章 Java 包装类(1.1)

一、包装类

1.1、基本数据类型与其包装类

Java是一种面向对象的编程语言,但是Java中的基本数据类型却不是面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,Java为每个基本数据类型设计了一个对应的类,这些和基本数据类型一一对应的类(共8个)统称为包装类(Wrapper Class)。包装类均位于java.lang包下,包装类和基本数据类型的对应关系如下表所示:

基本数据类型 包装类
boolean java.lang.Boolean
char java.lang.Character
Byte java.lang.Byte
short java.lang.Short
int java.lang.Integer
long java.lang.Lang
float java.lang.Float
double java.lang.Double
在这八个包装类中,除了java.lang.Character类和java.lang.Integer类外,其他六个类的类名和其所对应的基本数据类型一致,只是类名的第一个字母大写了。

在这些包装类中,表示数字的包装类都继承了java.lang.Number类,如图:

1.2、包装类的实例化

Java中,实例化包装类的对象非常方便,这里介绍几种常用的方式。

一》,通过使用new关键字实例化对象。
下面是一个示例:
public class Test1 {
public static void main(String[] args) {
// 通过new关键字实例化一些包装类的对象
Boolean boolean1 = new Boolean(true);
Boolean boolean2 = new Boolean(“随便”);
Character character1 = new Character(‘a’);
Byte byte1 = new Byte((byte)1); // 构造方法需要的参数为byte类型,字面量1为int类型,需要强制类型转换
Byte byte2 = new Byte(“1”);
Short short1 = new Short((short)2); // 构造方法需要的参数为short类型,字面量2为int类型,需要强制类型转换
Short short2 = new Short(“2”);
Integer integer1 = new Integer(3);
Integer integer2 = new Integer(“3”);
Long long1 = new Long(4); // 构造方法需要的参数为long类型,字面量4为int类型,这里自动类型转换了
Long long2 = new Long(“4”);
Float float1 = new Float(5.0f); // 这里使用new Float(5.0)也是可以的,Float类提供了以double类型作为参数的构造方法
Float float2 = new Float(“5.0”);
Double double1 = new Double(6.0);
Double double2 = new Double(“6.0”);
// 打印这些包装类对象(正常输出即可。)
}
}
解释:

本例演示了通过使用new关键字实例化各包装类的对象。
除了java.lang.Character类外,其他包装类都至少提供了两个构造方法,其中一个使用基本数据类型的值作为参数,另一个使用字符串作为参数。
对于java.lang.Boolean类型,其以字符串作为参数的构造方法当传入的参数为"true"(不区分大小写)时,实例化出的对象代表true,而是用其它字符串作为参数时,实例化出的对象均代表false。
通过观察各包装类对象的打印结果,不难发现,各包装类中的toString()方法均已被重写。

二》,通过各包装类中重载过的valueOf()方法获得实例化的对象。
下面是一个示例:
public class Test2 {
public static void main(String[] args) {
// 通过各包装类的重载的valueOf()方法获取一些包装类的对象
Boolean boolean1 = Boolean.valueOf(true);
Boolean boolean2 = Boolean.valueOf(“随便”);
Character character1 = Character.valueOf(‘c’);
Byte byte1 = Byte.valueOf((byte)1); // valueOf(byte b)方法需要的参数为byte类型,字面量1为int类型,需要强制类型转换
Byte byte2 = Byte.valueOf(“1”);
Short short1 = Short.valueOf((short)2); // valueOf(short s)方法需要的参数为short类型,字面量2为int类型,需要强制类型转换
Short short2 = Short.valueOf(“2”);
Integer integer1 = Integer.valueOf(3);
Integer integer2 = Integer.valueOf(“3”);
Long long1 = Long.valueOf(4); // valueOf(long l)方法需要的参数为long类型,字面量4为int类型,这里自动类型转换了
Long long2 = Long.valueOf(“4”);
Float float1 = Float.valueOf(5.0f);
Float float2 = Float.valueOf(“5.0”);
Double double1 = Double.valueOf(6.0);
Double double2 = Double.valueOf(“6.0”);
// 打印这些包装类对象

解释:

本例演示了通过各包装类中重载过的valueOf()方法获得实例化的对象。
除了java.lang.Character类外,其他包装类都至少提供了两个重载的valueOf()方法,其中一个使用基本数据类型的值作为参数,另一个使用字符串作为参数。
对于java.lang.Boolean类型,其valueOf(String s)方法当传入的参数为"true"(不区分大小写)时,实例化出的对象代表true,而是用其它字符串作为参数时,实例化出的对象均代表false。
下面是另一个示例:
public class Test3 {
public static void main(String[] args) {
// 通过valueOf(int i)方法获取一些Integer类的对象
Integer integer1 = Integer.valueOf(100);
Integer integer2 = Integer.valueOf(100);
Integer integer3 = Integer.valueOf(128);
Integer integer4 = Integer.valueOf(128);

    // == 操作符比较
    System.out.println("(integer1 == integer2) = " + (integer1 == integer2));
    System.out.println("(integer3 == integer4) = " + (integer3 == integer4));
    
    // equals(Object obj)方法比较
    System.out.println("integer1.equals(integer2) = " + integer1.equals(integer2));
    System.out.println("integer3.equals(integer4) = " + integer3.equals(integer4));
}

}
执行输出结果:
(integer1 == integer2) = true
(integer3 == integer4) = false
integer1.equals(integer2) = true
integer3.equals(integer4) = true
解释:
观察本例,变量integer1和integer2都是通过java.lang.Integer类的静态方法valueOf(int i)获得的,包装的数字都是100,使用操作符比较变量integer1和integer2,得到的结果是true;变量integer3和integer4同样都是通过java.lang.Integer类的静态方法valueOf(int i)获得的,只不过包装的数字都是128,使用操作符比较它们时,得到的结果却是false。本质上,变量integer1和integer2引用了同一块内存地址编号,而变量integer3和integer4则分别引用了不同的内存地址编号。产生这种现象的原因是,java.lang.Integer类中包含一个静态成员内部类IntegerCache,该类中有一个java.lang.Integer类型的数组cache,该数组中保存着一系列的java.lang.Integer类对象,依次包装了从-128~127(默认)这一范围内的数字,作为缓存。当使用valueOf(int i)获取java.lang.Integer类对象时,会先判断前述的缓存中是否有对应的对象,有则直接返回,没有则实例化一个新的java.lang.Integer类对象返回。包装类java.lang.Character、java.lang.Byte、java.lang.Short、java.lang.Long中都有类似的机制。
如果要比较包装类对象所包装的值是否相同,需要使用equals(Object obj)方法。各包装类的equals(Object obj)方法均已被重写。
三》,直接使用基本数据类型的字面量值赋值,获得包装类对象。
下面是一个示例:
public class Test4 {
public static void main(String[] args) {
// 使用基本数据类型的字面量值赋值,获得包装类对象
Boolean boolean1 = true;
Character character1 = ‘c’;
Byte byte1 = 1;
Short short1 = 2;
Integer integer1 = 3;
Long long1 = 4L;
Float float1 = 5.0f;
Double double1 = 6.0;
// 打印这些包装类对象

}

}
执行输出结果:

解释:

本例演示了直接使用基本数据类型的字面量值赋值,获得包装类对象。这也是最常用的方法。

1.3、包装类的作用

Java中,包装类有许多用途。
一》,包装类包含对应基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法 。
下面是一个示例:
public class Test5 {
public static void main(String[] args) {
// byte
System.out.println(“基本类型:byte 二进制位数:” + Byte.SIZE);
System.out.println(“包装类:java.lang.Byte”);
System.out.println(“最小值:Byte.MIN_VALUE=” + Byte.MIN_VALUE);
System.out.println(“最大值:Byte.MAX_VALUE=” + Byte.MAX_VALUE);
System.out.println();

    // short
    System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
    System.out.println("包装类:java.lang.Short");
    System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
    System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
    System.out.println();

    // int
    System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
    System.out.println("包装类:java.lang.Integer");
    System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
    System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
    System.out.println();

    // long
    System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
    System.out.println("包装类:java.lang.Long");
    System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
    System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
    System.out.println();

    // float
    System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
    System.out.println("包装类:java.lang.Float");
    System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
    System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
    System.out.println();

    // double
    System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
    System.out.println("包装类:java.lang.Double");
    System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
    System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
    System.out.println();

    // char
    System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
    System.out.println("包装类:java.lang.Character");
    // 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
    System.out.println("最小值:Character.MIN_VALUE=" + (int) Character.MIN_VALUE);
    // 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
    System.out.println("最大值:Character.MAX_VALUE=" + (int) Character.MAX_VALUE);
}

}
执行输出结果:

基本类型:byte 二进制位数:8
包装类:java.lang.Byte
最小值:Byte.MIN_VALUE=-128
最大值:Byte.MAX_VALUE=127

基本类型:short 二进制位数:16
包装类:java.lang.Short
最小值:Short.MIN_VALUE=-32768
最大值:Short.MAX_VALUE=32767

基本类型:int 二进制位数:32
包装类:java.lang.Integer
最小值:Integer.MIN_VALUE=-2147483648
最大值:Integer.MAX_VALUE=2147483647

基本类型:long 二进制位数:64
包装类:java.lang.Long
最小值:Long.MIN_VALUE=-9223372036854775808
最大值:Long.MAX_VALUE=9223372036854775807

基本类型:float 二进制位数:32
包装类:java.lang.Float
最小值:Float.MIN_VALUE=1.4E-45
最大值:Float.MAX_VALUE=3.4028235E38

基本类型:double 二进制位数:64
包装类:java.lang.Double
最小值:Double.MIN_VALUE=4.9E-324
最大值:Double.MAX_VALUE=1.7976931348623157E308

基本类型:char 二进制位数:16
包装类:java.lang.Character
最小值:Character.MIN_VALUE=0
最大值:Character.MAX_VALUE=65535

下面是另一个示例:
public class Test6 {
public static void main(String[] args) {
// 通过包装类对象获取对应其他基本类型的值
Short num1 = 1;
byte num2 = num1.byteValue();
System.out.println("num2 = " + num2);
Integer num3 = 25;
float num4 = num3.floatValue();
System.out.println("num4 = " + num4);

    // 比较两个基本类型的大小
    int num5 = 12, num6 = 21;
    int max = Integer.max(num5, num6);
    System.out.println("max = " + max);
    int min = Integer.min(num5, num6);
    System.out.println("min = " + min);

    // 获取2进制、8进制、16进制表示的字符串
    int num7 = 100;
    String binaryString = Integer.toBinaryString(num7);
    System.out.println("binaryString = " + binaryString);
    String octalString = Integer.toOctalString(num7);
    System.out.println("octalString = " + octalString);
    String hexString = Integer.toHexString(num7);
    System.out.println("hexString = " + hexString);

    // 两个基本类型的加法
    double num8 = 13.5, num9 = 30.8;
    double sum = Double.sum(num8, num9);
    System.out.println("sum = " + sum);
}

}
执行输出结果:

num2 = 1
num4 = 25.0
max = 21
min = 12
binaryString = 1100100
octalString = 144
hexString = 64
sum = 44.3
说明:

本例演示了包装类中提供的一些基本的关于数字处理的方法,如数字类型之间的转换、数字比较、数字在不同进制之间的转换等。
本例中的演示过的byteValue()方法、floatValue()方法均继承自java.lang.Number类。java.lang.Number类中提供了一些常用API,大多是抽象的,方便各包装类重写后用于获取对应的各种基本数据类型的值,这些API如下:
方法 返回值 方法说明
byteValue() byte 返回该Number对象封装的数字,作为一个byte类型的值,这可能涉及舍入或截断
shortValue() short 返回该Number对象封装的数字,作为一个short类型的值,这可能涉及舍入或截断
intValue() int 返回该Number对象封装的数字,作为一个int类型的值,这可能涉及舍入或截断
longValue() long 返回该Number对象封装的数字,作为一个long类型的值,这可能涉及舍入或截断
floatValue() float 返回该Number对象封装的数字,作为一个float类型的值,这可能涉及舍入
doubleValue() double 返回该Number对象封装的数字,作为一个double类型的值,这可能涉及舍入
二》、字符串(String)转换为基本数据类型,需要借助包装类。
下面是一个示例:
public class Test7 {
public static void main(String[] args) {
// 通过各包装类的parseXXX()方法将字符串转换为基本数据类型
byte num1 = Byte.parseByte(“1”);
short num2 = Short.parseShort(“2”);
int num3 = Integer.parseInt(“3”);
long num4 = Long.parseLong(“4”);
float num5 = Float.parseFloat(“5.0”);
double num6 = Double.parseDouble(“6.0”);
boolean boolean1 = Boolean.parseBoolean(“true”);
boolean boolean2 = Boolean.parseBoolean(“随便”);
// char类型直接使用字符串的charAt(int index)方法
char char1 = “hello world”.charAt(1);

    // 打印
}

}
执行输出结果:

num1 = 1
num2 = 2
num3 = 3
num4 = 4
num5 = 5.0
num6 = 6.0
boolean1 = true
boolean2 = false
char1 = e

需要注意的是,在将字符串(String)转换为基本数据类型的过程中,如果字符串本身无法转换,会抛出NumberFormatException异常,这是一个运行时异常。对于除了"true"以为的任意字符串或null,使用Boolean.parseBoolean(String s)方法获得的布尔值都将是false。
细心的开发者应该发现,在前文中包装类的实例化这一小节内容中,各包装类中均有重载的构造方法及重载的valueOf()方法可以将字符串当作参数,事实上,这些方法内部都在调用各包装类对应的parseXXX()方法,先将字符串转换为基本数据类型的值,然后再实例化包装类的对象。
三》、包装类作为和基本数据类型对应的引用类型存在,方便涉及到对象的操作。这一方面的作用在后续的章节中将会看到。

1.4、装箱和拆箱

java中的数据类型分为两大类,一类是基本数据类型,另一类是引用数据类型,如类、接口、数组、枚举。
无论是基本数据类型还是引用数据类型,它们都是Object类的子类。在程序编写过程中经常要将基本数据类型和引用数据类型进行互相转换,因此引入装箱和拆箱来完成此操作。

装箱(inboxing):将基本数据类型封装为包装类对象(将基本类型的数据转换为引用数据类型的数据);
拆箱(unboxing):将包装类中包装的基本数据类型数据取出(将引用类型的数据转换为基本数据类型的数据)。
注意:自动装箱和自动拆箱即装箱和拆箱的过程都是自发完成的。
自动装箱和自动拆箱是一种编译器的机制,自动装箱本质上是在编译过程中,在需要装箱的地方调用各包装类对应的valueOf()方法,而自动拆箱本质上是在编译过程中,在需要拆箱的地方调用各包装类对应的xxxValue()方法(如Integer类的对象在自动拆箱时会调用intValue()方法,Float类的对象在自动拆箱时会调用floatValue()方法)。

例:
public class Test8 {
public static void main(String[] args) {
int i = 1; //定义基本数据类型的变量i
Object obj = null;//定义引用数据类型的变量obj
Obj = i; //装箱
i = (int)obj; //拆箱
}
}

public class Test9 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(25); //装箱,add(Object value)方法的参数是Object类型,即引用类型,赋的值是基本类型中的整型值25.
int age = (int)list.get(0);//拆箱,get(int index)返回值类型是Object,经过强制转换为int类型后赋值给age.
}
}

public class Test10 {
public static void main(String[] args) {
// 直接使用基本数据类型(8)的字面量值赋值,获得包装类对象(byte1),就是一种自动装箱的过程
Byte byte1 = 8;

    // 将一个包装类对象(integer1)直接赋值给一个基本数据类型的变量,会自动拆箱
    Integer integer1 = new Integer(1);
    int num1 = integer1;

    // 一个包装类对象与一个基本数据类型的数值进行+运算,包装类对象也会被自动拆箱
    Float float1 = new Float(1.5f);
    float num2 = 1 + float1;
}

}
解释:

直接使用基本数据类型的字面量值赋值,获得包装类对象,就是一种自动装箱(inboxing)的过程。本例中的代码Byte byte1 = 8编译后对应的代码为Byte byte1 = Byte.valueOf(8)。

将一个包装类对象直接赋值给一个基本数据类型的变量,会自动拆箱(unboxing)。本例中的代码int num1 = integer1编译后对应的代码为int num1 = integer1.intValue()。

一个包装类对象与一个基本数据类型的数值使用+、-、*、\、==等操作符进行运算时,包装类对象也会被自动拆箱。本例中的代码float num2 = 1 + float1编译后对应的代码为float num2 = 1 + float1.floatValue()。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值