本文为读书笔记
1. 泛型擦除
擦除式泛型的实现几乎只需要在Javac编译器上做出改进即可,不需要改动字节码、不需要改动Java虚拟机,也保证了以前没有使用泛型的库可以直接运行在Java 5.0之上。
泛型擦除的实现:
擦除前:
擦除后:
可见:
java的类型擦除是把T 在编译时直接抹去,编程类似于ArrayList list 这样的裸类型;而在调用的时候进行强制类型转换;
但是问题出现了:
这样的代码目前java是不支持的,想要用基本类型的集合类,得用包装类,那么问题就出现,每次调用集合类都要进行一次拆箱装箱,这无疑是对性能的一种开销;
2. 自动拆箱装箱
装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。
以及:
第一个true:
反编译一下看调用了什么:
执行了 Integer.valueof这个static方法
private static class IntegerCache {
static final int low = -128;
static final int high;
static {
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
}
一般情况下是127
所以可见,返回的是缓存池里池内同一个对象
超过范围:-128-127 之后就不会从缓存池里取了;
故第二个 false 也能解释了;
第三四个true:
调用的是Integer.intValue来获取值,最后判等就行了故为true
**注意 == 是值相等 **
再来看g 由于 拆箱装箱,所以 左边是一个long的 3 == 右边 int 3
相等
最后一个:
调用的是long的equals
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
很明显不是 Long类型,故false
由此可以得出结论:
数值类型包装类 装箱(设置值) valueof() 拆箱(获取值) xxxValue()
== 值相等的前提是 左右触发了拆箱 ==做值相等,而不是地址相等
equals为重写方法,调用相关基本类型的包装类方法:
首先判断实例类型,再判断值
给大家总结以下 :
+会触发语法糖 反编译就是IntValue,因为CPU只认识int类型
无+就是valueOf其中涉及到Integer的缓存值
Integer.equals Integer重写了方法,如果是同类型比较则比较value值。
3. 堆污染
什么时候会发生堆污染呢?
当参数化类型的变量指向一个非参数化类型的对象时,会发生堆污染。如果程序在执行某些操作,在编译时产生 unchecked warning (未经检查的警告),就会出现这种情况。无论是 编译时 还是 运行时 ,如果无法验证一个涉及参数化的类型的操作(例如:类型强转、方法调用)是否正确,就会产生一个 unchecked warning 。
也就是说,当一个参数化的类型无法再编译或运行时被确定,会产生一个 unchecked warning ,这时,就发生了堆污染。
前面有提到,由于泛型擦除,泛型是不能显示的完成转型、instanceof 和 new 表达式 的操作的。比如下面的例子:
// 语句 1
List list = new ArrayList<Integer>();
// 语句 2 -- unchecked warning
List<String> strList = list;
由于语句 1 声明了一个无泛型的对象 list(实际存储的是Integer类型的参数),语句 2 将无泛型的 list 对象,赋给了 String 类型 的泛型变量 strList,此处会发生堆污染。为什么呢?
由于泛型擦除,new ArrayList() 和 List strList 会被擦除为 ArrayList 和 List,当 list 指向 strList 时,编译器是无法确定 list 和 strList 的参数类型的,因为在运行时 list 的类型信息 “Integer” 和 strList 的类型信息 “String” 都已经被擦除了,这时就会产生 unchecked warning ,自然就会发生 堆污染了。
在正常情况下,当所有代码同时编译时,编译器会发出未经检查的警告,以引起对潜在堆污染的注意。如果单独编译代码的各个部分,则很难检测到堆污染的潜在风险。如果确保代码在没有警告的情况下编译,则不会发生堆污染。