1.为什么阿里巴巴强制要求使用包装类型定义属性?
我认为主要有以下几个方面的原因:
- 默认值问题:使用基本数据类型定义属性时,如果没有给属性赋初始值,会使用默认值(如 int 的默认值为 0),而使用包装类型定义属性,如果没有给属性赋初始值,属性的值为 null,这样可以更加清晰地表达属性的状态,在一些业务场景上,null是有实际业务含义的。
- 拆箱问题:在一些特定场景下,如果使用基本数据类型定义属性,需要进行多次装箱和拆箱操作,这个操作会带来额外的性能开销和代码复杂度。而使用包装类型定义属性,可以避免这个问题,提高代码的效率和可读性。在进行拆箱操作时,如果包装类对象为null,会导致NullPointerException异常。
- 泛型中只能使用对象:Java 中的泛型中只能使用对象类型,如果要在泛型编程中使用基本类型,就必须使用对应的包装类型。
- 更多的API:包装类型提供了一些额外方法和属性比如 equals()、hashCode()、toString(),这些方法在某些特定场景中会比较有用。
知识扩展
(1)拆箱和装箱
概念:在Java中,拆箱(Unboxing)和装箱(Boxing)是用于基本数据类型和对应的包装类之间进行相互转换的过程,装箱是指将基本数据类型转换为对应的包装类对象(如int->Integer、double->Double等),拆箱是指把包装类对象转换成基本数据类型。
装箱
手动装箱
int num = 10;
Integer obj = new Integer(num); // 使用构造函数
Integer obj2 = Integer.valueOf(num); // 使用静态工厂方法
自动装箱
int num = 10;
Integer obj = num; // 自动装箱,编译器会自动将基本类型转换为对应的包装类对象
拆箱
手动拆箱
Integer obj = new Integer(10);
int num = obj.intValue(); // 调用intValue()方法获取基本类型的值
自动拆箱
Integer obj = new Integer(10);
int num = obj; // 自动拆箱,编译器会自动将包装类对象转换为对应的基本类型
在进行拆箱操作时,如果包装类对象为null
,会导致NullPointerException
异常
Integer obj = null;
int num = obj; // 自动拆箱,由于obj为null,会触发NullPointerException异常
因此需要做额外的判断比较麻烦
Integer obj = null;
if (obj != null) {int num = obj; // 自动拆箱,这里会跳过拆箱操作,避免了NullPointerException异常
}
(2)Java 中的泛型
- 泛型(Generics)是一种强类型检查机制,在编译时期提供类型安全性检查,并在运行时避免类型转换错误。泛型在 Java 中主要应用于类、接口和方法。
- 泛型主要是针对对象类型(引用类型)而设计的,而不是基本数据类型(如
int
、char
等)。这是因为 Java 的泛型实现是通过类型擦除(Type Erasure)来实现的,即在编译时将泛型类型信息擦除,生成的字节码中只保留原始类型。虽然无法直接应用于基本数据类型,但Java 提供了对应的包装类来处理基本数据类型的泛型需求。例如,Integer
是int
的包装类,可以作为泛型类型使用。
为什么类型擦除要求是对象类型?
先看下面案例,我们下意识认为这两个集合是不同的类型,运行结果竟然是true。
public class GenericsTest {public static void main(String[] args) {List<Integer> integers = new ArrayList<>();List<String> strings = new ArrayList<>();System.out.println(integers.getClass().equals(strings.getClass()));}
}
在编辑阶段会进行类型检查,编辑通过后编译器会把类型擦除,在运行阶段时,对JVM来说就没有什么泛型类型的对象,所有的对象都是属于普通类。 List和List被擦除类型后,类型都是List类型(被擦除后的类型,如这里的List统称叫原始类型)
其中的泛型参数都会被替换成它的第一个上界
没有边界只时就会被替换成底层父类Object。发现和Java1.5之前还没泛型时的代码是一致的。这也是类型擦除的目的:向低版本兼容
总结:
泛型不支持基本数据类型,只支持引用类型,因为泛型最终被擦除成具体的类型,具体的类型的顶层是Object,而Object不能存储基本数据类型的值(int等基本数据类型)。
Java 泛型弊端:
- 不能支持基本数据类型;
- 只有原始类型的class;
- 不能实例化参数类型;
- 不能实例化泛型数组;
不能支持基本数据类型:
只有原始类型的class:
不能实例化参数类型:
不能实例化泛型数组:
最后我们可以通过反射机制恢复这些泛型信息