包装类
什么是包装类
在Java中,包装类(Wrapper Class)是指那些用于包装基本数据类型(如 int
、double
、char
等)的类。Java为每个基本数据类型提供了对应的包装类,使得基本类型也可以拥有对象的特征,比如可以被用来创建对象数组、作为方法的返回类型、实现接口等。
基本数据类型及其对应的包装类:
int
-Integer
double
-Double
char
-Character
boolean
-Boolean
byte
-Byte
short
-Short
long
-Long
float
-Float
包装类通常具有以下特点:
- 构造函数:包装类提供了接受基本数据类型参数的构造函数,用于创建包装类的对象。
- 静态方法:包装类提供了静态方法
valueOf()
,可以将基本数据类型转换为对应的包装类对象。 - 实例方法:包装类提供了实例方法
xxxValue()
(如intValue()
、doubleValue()
等),用于将包装类对象转换回基本数据类型。 - 缓存:对于
Integer
和Long
类型,Java 虚拟机(JVM)会缓存从-128
到127
(对于Integer
)和-128
到127
(对于Long
)范围内的实例,以提高性能。 - 比较:包装类重写了
equals()
方法,使得可以比较两个包装类对象所包装的值是否相等。
示例代码:
public class WrapperClassExample {
public static void main(String[] args) {
// 使用构造函数创建包装类对象
Integer integerObject = new Integer(123);
Double doubleObject = new Double(45.67);
// 使用 valueOf() 方法创建包装类对象
Integer anotherInteger = Integer.valueOf(789);
Double anotherDouble = Double.valueOf(1011.12);
// 使用 xxxValue() 方法将包装类对象转换回基本数据类型
int intValue = integerObject.intValue();
double doubleValue = doubleObject.doubleValue();
// 比较两个包装类对象
boolean isEqual = integerObject.equals(anotherInteger);
System.out.println("Integer value: " + intValue);
System.out.println("Double value: " + doubleValue);
System.out.println("Are the two Integer objects equal? " + isEqual);
}
}
包装类的特点
包装类(Wrapper Class)在Java中的下特点:
-
自动装箱与拆箱:
- 自动装箱(Autoboxing):基本数据类型可以直接赋值给对应的包装类对象,编译器会自动调用相应的
valueOf()
方法。 - 自动拆箱(Unboxing):包装类对象可以直接赋值给对应的基本数据类型,编译器会自动调用相应的
xxxValue()
方法。
- 自动装箱(Autoboxing):基本数据类型可以直接赋值给对应的包装类对象,编译器会自动调用相应的
-
数值表示范围:
- 包装类可以表示基本数据类型能表示的所有值,以及额外的
null
值。
- 包装类可以表示基本数据类型能表示的所有值,以及额外的
-
参与集合操作:
- 包装类对象可以作为集合(如
List
、Set
、Map
)的元素,而基本数据类型不能。
- 包装类对象可以作为集合(如
-
实现接口:
- 包装类实现了一些Java接口,例如:
Integer
、Double
、Float
和Long
实现了Comparable
接口,可以比较它们所包装的数值大小。Character
实现了CharSequence
和Comparable
接口。
- 包装类实现了一些Java接口,例如:
-
方法丰富:
- 包装类提供了一些有用的方法,例如
toString()
、hashCode()
、equals()
等,以及一些特定于类型的便利方法,如Character.isLetter()
等。
- 包装类提供了一些有用的方法,例如
-
数值缓存:
- 对于
Integer
和Long
类型,JVM 会缓存一定范围内的实例(Integer
缓存-128
到127
,Long
缓存-128
到127
),以提高性能。
- 对于
-
与字符串的转换:
- 包装类提供了方便的方法将基本数据类型转换为字符串,如
Integer.toString(int i)
。
- 包装类提供了方便的方法将基本数据类型转换为字符串,如
-
静态工厂方法:
- 包装类提供了静态工厂方法来创建实例,如
Integer.valueOf(int i)
和Character.valueOf(char c)
。
- 包装类提供了静态工厂方法来创建实例,如
-
类型转换:
- 包装类之间可以进行类型转换,但需要注意可能发生的精度损失或溢出。
-
null 安全:
- 包装类对象可以为
null
,而基本数据类型不能。
- 包装类对象可以为
-
equals() 方法:
- 包装类的
equals()
方法比较的是它们所包装的值是否相等,而不是对象引用是否相同。
- 包装类的
-
hashCode() 方法:
- 包装类的
hashCode()
方法返回的是它们所包装的值的哈希码。
- 包装类的
基本数据类型与包装类
Java 中的基本数据类型(Primitive Data Types)和包装类(Wrapper Classes)是密切相关的,但它们有一些关键的区别和联系:
基本数据类型:
- 基本数据类型是 Java 语言预定义的,用于表示最简单的数据单元。
- 它们包括:
boolean
、char
、byte
、short
、int
、long
、float
、double
。 - 基本数据类型直接存储原始数据,没有方法或属性。
包装类:
- 包装类是 Java 提供的,用于“包装”基本数据类型的类。
- 每个基本数据类型都有对应的包装类:
Boolean
、Character
、Byte
、Short
、Integer
、Long
、Float
、Double
。 - 包装类提供了构造函数、方法、属性,可以进行更复杂的操作。
基本数据类型与包装类的区别:
- 存储方式:基本数据类型直接存储值,而包装类存储对象引用。
- 默认值:基本数据类型的变量可以不初始化,有默认值(例如,
int
的默认值是0
),包装类对象必须被显式初始化。 - 性能:基本数据类型的操作通常比包装类对象的操作简单,因为它们不需要对象的创建和销毁。
- 内存使用:基本数据类型使用的内存较少,而包装类对象使用的内存更多,因为它们是对象。
- 可空性:基本数据类型的变量不能为
null
,而包装类的对象可以为null
。
基本数据类型与包装类的联系:
- 自动装箱与拆箱:Java 5 引入了自动装箱(将基本数据类型转换为对应的包装类对象)和拆箱(将包装类对象转换为对应的基本数据类型)机制。
- 数值范围:包装类的数值范围与对应的基本数据类型相同,但包装类可以表示
null
。 - 方法和属性:包装类提供了方法和属性,可以对基本数据类型进行更复杂的操作。
- 集合框架:包装类可以被用作集合的元素,而基本数据类型不能直接作为集合的元素。
示例代码:
public class PrimitiveVsWrapper {
public static void main(String[] args) {
int primitiveInt = 10; // 基本数据类型
Integer wrapperInt = 20; // 包装类
// 自动装箱
Integer autoboxedInt = 30;
// 自动拆箱
int autounboxedInt = autoboxedInt;
System.out.println("Primitive int: " + primitiveInt);
System.out.println("Wrapper int: " + wrapperInt);
System.out.println("Autoboxed int: " + autoboxedInt);
System.out.println("Autounboxed int: " + autounboxedInt);
}
}
包装类共同点
Java 中的包装类虽然各自代表不同的基本数据类型,但它们有一些共同的特点和行为:
-
继承关系:所有的包装类都继承自
java.lang.Number
类,这意味着它们共享Number
类的一些方法,如doubleValue()
、floatValue()
、intValue()
、longValue()
和shortValue()
等。 -
构造函数:每个包装类都提供了一个或多个构造函数,允许你创建该类型的实例。
-
valueOf 方法:每个包装类都有一个静态的
valueOf
方法,它接受一个基本数据类型的参数,并返回对应的包装类实例。例如,Integer.valueOf(int i)
。 -
parseXxx 方法:大多数包装类提供了
parseXxx
方法,用于将字符串解析为基本数据类型的值。例如,Integer.parseInt(String s)
。 -
equals 和 hashCode 方法:包装类重写了
equals(Object obj)
方法,以比较两个包装类对象所包装的值是否相等,而不是比较对象引用。同时,它们也重写了hashCode()
方法,以提供与equals
一致的哈希码。 -
toString 方法:包装类提供了
toString()
方法,用于返回包装值的字符串表示。 -
compareTo 方法:除了
Boolean
和Character
之外,所有的包装类都实现了Comparable
接口,并提供了compareTo()
方法,允许按自然顺序比较包装的值。 -
类型转换方法:包装类提供了类型转换的方法,如
byteValue()
、shortValue()
、intValue()
、longValue()
、floatValue()
和doubleValue()
,允许将包装类对象转换为不同的数值类型。 -
缓存实例:对于
Integer
和Long
类型,JVM 会缓存一定范围内的实例(Integer
缓存-128
到127
,Long
缓存-128
到127
),以提高性能。 -
null 安全性:包装类的对象可以为
null
,这与基本数据类型的变量不同,后者不能为null
。 -
静态字段:包装类定义了表示其对应基本数据类型最小值和最大值的静态字段,如
Integer.MIN_VALUE
和Integer.MAX_VALUE
。 -
size 方法:大多数包装类提供了一个静态的
size()
方法,返回该类型的位数,如Integer.SIZE
返回 32。
自动装箱/拆箱
自动装箱(Autoboxing)和自动拆箱(Unboxing)是Java 5及以后版本引入的特性,它们允许基本数据类型和对应的包装类之间的无缝转换。
自动装箱(Autoboxing)
自动装箱是指自动将基本数据类型的值转换为对应的包装类对象。这个过程是编译器自动完成的,无需程序员显式进行转换。例如:
int i = 10; // 基本数据类型
Integer num = i; // 自动装箱,将 int 类型转换为 Integer 对象
在上面的例子中,整数 10
被自动转换为 Integer
类型的对象。
自动拆箱(Unboxing)
自动拆箱是指自动将包装类对象的值转换为对应的基本数据类型。与自动装箱相对应,这也是编译器自动完成的。例如:
Integer num = new Integer(20); // 包装类对象
int i = num; // 自动拆箱,将 Integer 对象转换为 int 类型
在这个例子中,Integer
对象 num
被自动转换为基本数据类型 int
。
特性和注意事项
- 自动装箱和拆箱使得基本数据类型和包装类之间的转换更加方便和直观。
- 自动装箱可能导致性能问题,因为涉及到对象的创建,尤其是在循环或大量数据处理时。在这种情况下,使用基本数据类型可能更优。
- 包装类可以为
null
,但基本数据类型不能。在使用自动拆箱时,如果包装类对象为null
,将会导致NullPointerException
。 - 自动装箱和拆箱在集合操作中特别有用,因为集合只能存储对象,不能直接存储基本数据类型。
示例代码
public class AutoboxingUnboxingExample {
public static void main(String[] args) {
// 自动装箱
int primitiveInt = 100;
Integer boxedInt = primitiveInt; // 无需显式调用 Integer.valueOf()
// 自动拆箱
Integer anotherBoxedInt = new Integer(200);
int anotherPrimitiveInt = anotherBoxedInt; // 无需显式调用 intValue()
// 使用自动装箱和拆箱在集合中存储基本数据类型的值
List<Integer> numbers = new ArrayList<>();
numbers.add(primitiveInt); // 装箱
numbers.add(boxedInt); // 已经是包装类对象
numbers.add(300); // 装箱
// 打印集合中的元素,演示自动拆箱
for (int number : numbers) {
System.out.println(number);
}
}
}
代码中,numbers
集合存储了 Integer
对象,但在遍历时,自动拆箱特性允许我们直接使用 int
类型的变量 number
来访问集合中的元素。