【Java】包装类

在这里插入图片描述

概述

Java 引入包装类的主要原因有三:

1、面向对象的需求

Java 的基本数据类型(如 int、double)不是对象,而 Java 的很多框架、集合(如 ArrayList、HashMap)只能存放对象。因此需要“包装”基本类型,使其能作为对象使用。

2、提供更多功能

包装类为基本类型提供了丰富的方法(如转换、比较、解析字符串等)。例如:

Integer.parseInt("123");
Character.isDigit('9');

3、支持泛型与集合框架

泛型不支持基本类型,因此必须使用包装类。例如:

List<Integer> list = new ArrayList<>(); // 不能使用 List<int>

包装类(Wrapper Class)是 Java 为每个基本数据类型提供的对应的引用类型(类)。

  • 将基本类型“封装”为对象;
  • 提供了操作基本类型的各种方法;
  • 支持自动拆箱/装箱(Java 5 引入)。

有哪些包装类

Java 为每一种基本数据类型都提供了对应的包装类:

基本类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

其中,除了 Character 和 Boolean,父类都是 Number

封装以后的,内存结构对比:

public static void main(String[] args){
	int num = 520;        // 栈
	Integer obj = new Integer(520); // 栈中是 obj 指针,指向堆中存放value的地址
}

装箱与拆箱

装箱:把基本类型转换成包装类对象。

✔ 旧方式(Java 5 之前,手动装箱)

int a = 10;
Integer integerObj = Integer.valueOf(a);  // 装箱

拆箱:把包装类对象转换为基本类型。

✔ 旧方式(Java 5 之前,手动拆箱)

Integer integerObj = Integer.valueOf(10);
int b = integerObj.intValue();  // 拆箱            xxxValue()

自动装箱与拆箱:从 Java 5 开始,编译器自动进行装箱和拆箱,无需手动调用 xxxValue()valueOf()

int a = 10;
Integer integerObj = a; // 自动装箱,相当于 Integer.valueOf(a)
Integer integerObj = 20;
int b = integerObj; // 自动拆箱,相当于 integerObj.intValue()
Integer i = 4; // 自动装箱,相当于 Integer i = Integer.valueOf(4);
i = i + 5;     // 等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5;
// 加法运算完成后,再次装箱,把基本数值转成对象。
Integer x = 5;
Integer y = 10;
int sum = x + y; // x 和 y 自动拆箱为 int

集合不能存基本类型,只能存对象:

List<Integer> list = new ArrayList<>();
list.add(100);  // 自动装箱为 new Integer(100)
int value = list.get(0); // 自动拆箱为 int

注意:只能与自己对应的类型之间才能实现自动装箱与拆箱。

Integer i = 1;
Double d = 1;       // 错误的,1是int类型

自定义包装类

Java 语言中已经提供了 8 个基本数据类型的包装类。但在某些业务场景下,你可能需要为特定数据结构或行为创建自己的包装对象,这就是 自定义包装类

简单来说:

👉 自定义包装类 = 对某个数据或对象进行“封装”,让它具有更丰富的行为或更安全的操作方式。

📌 场景 1:需要对数据进行额外校验

例如包裹一个年龄字段,要求只能在 0–150 之间。

📌 场景 2:需要不可变对象(Immutable)

像 Java 的 String 和包装类都是不可变的,你可以自己创建不可变数据。

📌 场景 3:需要实现某些自定义逻辑

例如:

  • 限制值域
  • 自动格式化数据
  • 在赋值时触发事件

📌 场景 4:提高可读性与领域建模能力(DDD)

如将 int price 替换为 Money 类型,更能表达语义。

下面示例创建一个包装整数的类 MyInteger

public class MyInteger {
    private int value;

    public MyInteger(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }
}
MyInteger num = new MyInteger(10);
System.out.println(num.getValue());  // 输出:10

加入校验(增强包装类的价值)

例如:年龄 Age 必须在 0–150 之间。

public class Age {
    private final int value;

    public Age(int value) {
        if (value < 0 || value > 150) {
            throw new IllegalArgumentException("Age must be between 0 and 150.");
        }
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }
}
Age age = new Age(25);
// Age age = new Age(200);  // 会报错

⚠️注意事项

✔ 一般建议包装类设计为不可变(Immutable)

将字段设为 final,避免并发问题。

✔ 重写 equals()hashCode()

如果希望对象能放入 HashMap / HashSet,需要:

@Override
public boolean equals(Object o) { ... }

@Override
public int hashCode() { ... }

✔ 考虑与原始类型的转换

例如:

public int toInt() { return value; }

✔ 考虑自动装箱功能

Java 的自动装箱无法应用于自定义类型,使用时需手动转换。

常用 API

最大值与最小值

所有数值型包装类都包含 MAX_VALUEMIN_VALUE 常量。

public class WrapperDemo1 {
    public static void main(String[] args) {
        System.out.println("Integer 最大值: " + Integer.MAX_VALUE);
        System.out.println("Integer 最小值: " + Integer.MIN_VALUE);

        System.out.println("Double 最大值: " + Double.MAX_VALUE);
        System.out.println("Double 最小值: " + Double.MIN_VALUE);

        System.out.println("Short 最大值: " + Short.MAX_VALUE);
        System.out.println("Short 最小值: " + Short.MIN_VALUE);
    }
}
字符大小写转换

Character 提供字符处理的静态方法:

方法说明
isUpperCase(char)判断是否大写
isLowerCase(char)判断是否小写
toUpperCase(char)转大写
toLowerCase(char)转小写
public class WrapperDemo2 {
    public static void main(String[] args) {
        char c1 = 'a';
        char c2 = 'Z';

        System.out.println(Character.isLowerCase(c1));  // true
        System.out.println(Character.isUpperCase(c2));  // true

        System.out.println(Character.toUpperCase(c1));  // A
        System.out.println(Character.toLowerCase(c2));  // z
    }
}
整数转不同进制

Integer 提供了三个常用静态方法:

方法说明
toBinaryString(int)转二进制
toOctalString(int)转八进制
toHexString(int)转十六进制
public class WrapperDemo3 {
    public static void main(String[] args) {
        int num = 100;

        System.out.println(Integer.toBinaryString(num)); // 1100100
        System.out.println(Integer.toOctalString(num));  // 144
        System.out.println(Integer.toHexString(num));    // 64
    }
}
字符串与基本类型互转

字符串 → 基本类型

使用 parseXxx() 方法:

int a = Integer.parseInt("123");
double b = Double.parseDouble("3.14");
boolean c = Boolean.parseBoolean("true");

基本类型 → 字符串

使用 String.valueOf() 或包装类的 toString()

String s1 = String.valueOf(123);
String s2 = Integer.toString(456);
比较
方法说明
equals(Object)比较值是否相等
compareTo(T another)比较大小(返回正/负/0)
public class WrapperDemo4 {
    public static void main(String[] args) {
        Integer x = 20;
        Integer y = 15;

        // 比较值是否相等
        System.out.println(x.equals(y));   // false

        // 比较大小
        System.out.println(x.compareTo(y));  // 1(大于)
        System.out.println(y.compareTo(x));  // -1(小于)
        System.out.println(x.compareTo(20)); // 0(相等)
    }
}

包装类对象特性

✨包装类缓存对象
包装类缓存对象
Byte-128~127
Short-128~127
Integer-128~127
Long-128~127
Float没有
Double没有
Character0~127
Booleantrue 和 false

举例

Integer a = 1;
Integer b = 1;
System.out.println(a == b);                            // true

Java中,`Integer`有一个缓存池,它会缓存`-128`到`127`之间的所有值。当你创建值在这个范围内的`Integer`对象时,Java会返回缓存中的对象,而不是创建一个新的对象。所以当`a`和`b`都赋值为`1`时,它们引用的是同一个对象。因此`a == b`为`true`,因为`==`比较的是对象的引用是否相同。

Integer i = 128;
Integer j = 128;
System.out.println(i == j);                            // false

Java中,Integer对象的缓存池只缓存-128127之间的值。128超出了这个范围,因此i和j是两个不同的对象。即使它们的值相同,但它们指向不同的内存位置。所以i == j返回false,因为==比较的是引用是否相同。

Integer m = new Integer(1);                            // 新new的在堆中
Integer n = 1;                                         // 这个用的是缓冲的常量对象,在方法区
System.out.println(m == n);                            // false

new Integer(1)会强制创建一个新的Integer对象,而n = 1由于值在缓存范围内,会引用缓存中的Integer对象。所以m和n是两个不同的对象。即使它们的值相同,==比较的是引用,而不是值,因此结果为falseInteger x = new Integer(1);                            // 新new的在堆中
Integer y = new Integer(1);                            // 另一个新new的在堆中
System.out.println(x == y);                            // false

new Integer(1)会创建两个不同的Integer对象,x和y指向不同的内存位置。即使它们的值相同,==比较的是对象引用,而不是对象的值。因此,x == y返回false
Double d1 = 1.0;
Double d2 = 1.0;
System.out.println(d1==d2); // false 比较地址,没有缓存对象,每一个都是新new的

Double没有像Integer那样有值缓存池,==运算符比较的是对象引用,而不是值。即使d1和d2的值相同,它们仍然是不同的对象,因此d1 == d2返回false
类型转换问题
Integer i = 1000;
double j = 1000;  // 或 1000.0
System.out.println(i == j);  // true,在进行 == 比较时,Java会进行自动拆箱,将 Integer 拆箱为 int,并且将 int 转换为 double。最终比较的是数值,而不是对象引用。
Integer i = 1000;
int j = 1000;
System.out.println(i == j);  // true
Integer i = 1;
Double d = 1.0
System.out.println(i == d);  // 编译报错,Java 不允许直接比较不同类型的包装类对象,即使它们的值相同。因此,编译器会报错,提示类型不匹配。如果你想要比较它们的数值,需要将它们转换成相同的类型。可以通过拆箱和类型转换来实现。
✨包装类对象不可变

一旦包装类对象被创建,它内部保存的值就不能再被修改。如果看起来“修改”了包装类对象,其实是创建了一个新的对象。

public class WrapperTest {
    public static void main(String[] args) {
        Integer num = 10;
        System.out.println("调用前 num = " + num);

        changeValue(num);

        System.out.println("调用后 num = " + num);
    }

    public static void changeValue(Integer x) {
        x = 20;   // 实际上是让 x 指向一个新的 Integer 对象
        System.out.println("方法内 x = " + x);
    }
}

调用前 num = 10
方法内 x = 20
调用后 num = 10
public class Test2 {
    public static void main(String[] args) {
        Integer i = 5;
        increment(i);
        System.out.println(i); // 输出还是 5
    }

    public static void increment(Integer x) {
        x++;      // x++ 会创建一个新的 Integer 对象
    }
}
### Java 包装详解 Java 中的包装(Wrapper Class)是用来将基本数据型(Primitive Data Type)转换为对象(Object)的一种机制。包装的作用是提供一种方式,使得基本数据型可以像对象一样被操作,例如存储在集合中或进行其他面向对象的操作。 #### 1. 基本数据型与包装的关系 Java 提供了八种基本数据型及其对应的包装[^2]: - **byte** ↔ **Byte** - **short** ↔ **Short** - **int** ↔ **Integer** - **long** ↔ **Long** - **float** ↔ **Float** - **double** ↔ **Double** - **char** ↔ **Character** - **boolean** ↔ **Boolean** 这些包装都位于 `java.lang` 包中,因此不需要显式导入即可使用。 #### 2. 包装的功能 包装的主要功能包括以下几点: - 将基本数据型转换为对象。 - 提供方法来操作和转换基本数据型。 - 提供静态方法将字符串转换为基本数据型。 #### 3. 基本数据型与包装之间的转换 ##### (1) 基本数据型 → 包装 可以通过构造方法或自动装箱(Autoboxing)实现基本数据型到包装的转换。例如: ```java // 使用构造方法 Integer integer = new Integer(100); // 已过时,不推荐使用 // 自动装箱 Integer integerAutoBoxed = 100; // 推荐使用 ``` ##### (2) 包装 → 基本数据型 可以通过调用包装的 `xxxValue()` 方法或自动拆箱(Unboxing)实现包装到基本数据型的转换。例如: ```java Integer integer = new Integer(100); int primitiveInt = integer.intValue(); // 调用intValue()方法 int autoUnboxedInt = integer; // 自动拆箱 ``` #### 4. 包装与字符串的相互转换 ##### (1) 包装 → 字符串 可以通过 `String.valueOf()` 方法将包装转换为字符串。例如: ```java Integer integer = 100; String str = String.valueOf(integer); // 使用String的静态方法 ``` ##### (2) 字符串 → 包装 可以通过包装的 `parseXxx(String s)` 静态方法将字符串转换为包装。例如: ```java String str = "100"; int primitiveInt = Integer.parseInt(str); // 转换为基本数据型 Integer wrapperInt = Integer.valueOf(str); // 转换为包装 ``` #### 5. 包装的常用方法 以下是一些常用的包装方法: - **`compareTo()`**:用于比较两个对象的大小。 - **`equals()`**:用于判断两个对象是否相等。 - **`toString()`**:返回对象的字符串表示形式。 - **`hashCode()`**:返回对象的哈希码值。 #### 6. 注意事项 - **自动装箱与拆箱**:从 Java 5 开始支持自动装箱和拆箱,简化了代码编写,但需要注意潜在的性能问题。 - **缓存机制**:某些包装(如 `Integer`、`Boolean` 等)实现了缓存机制,避免频繁创建新对象。例如,`Integer` 在 -128 到 127 之间的值会被缓存[^1]。 - **空指针异常**:在使用自动拆箱时,如果包装对象为 `null`,会导致 `NullPointerException`。 ```java Integer a = null; int b = a; // 抛出NullPointerException ``` #### 7. 示例代码 以下是一个综合示例,展示如何使用包装进行型转换: ```java public class WrapperClassExample { public static void main(String[] args) { // 基本数据型转包装 Integer integer = Integer.valueOf(100); // 显式转换 Integer autoBoxed = 100; // 自动装箱 // 包装转基本数据型 int primitiveInt = integer.intValue(); // 显式转换 int autoUnboxed = integer; // 自动拆箱 // 包装转字符串 String str = String.valueOf(integer); // 字符串转包装 String strValue = "200"; Integer parsedInteger = Integer.valueOf(strValue); System.out.println("integer: " + integer); System.out.println("primitiveInt: " + primitiveInt); System.out.println("str: " + str); System.out.println("parsedInteger: " + parsedInteger); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shayudiandian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值