梦想还是要有的,万一忘了咋办?

0%

java泛型

关键词

  • 伪泛型
  • 针对引用的检查
  • 类型擦除
  • 协变
  • 多态的冲突

介绍

java泛型是伪泛型,java文件编译时会进行类型擦除这样生成的class文件不再包含任何泛型信息。
泛型价值:增加约束,让代码优雅(无需显式的类型转化)。

原始类型

1
2
3
4
5
6
7
8
9
10
11
12
abstract class Math<T> {
abstract T max(T t1, T t2);
}
-----字节码------
abstract max(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

abstract class Math2<T extends Number> {
abstract T max(T t1, T t2);
}
------字节码-----
abstract max(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;

Object 或者 Number 就是T 的原始类型。这是类型擦除的基础思路,也由此产生了多态冲突问题。

类型擦除

文字描述比较枯燥难懂,以下通过3个示例来介绍,类型擦除、针对引用有效、为什么叫做 伪泛型。

示例1

1
2
3
4
5
6
7
8
9
10
11
12
// 携带泛型的对象对应字节码完全一致。
List<String> strList = new ArrayList<String>();
List intList = new ArrayList();
---------字节码------------
NEW java/util/ArrayList
DUP
INVOKESPECIAL java/util/ArrayList.<init> ()V
ASTORE 1
NEW java/util/ArrayList
DUP
INVOKESPECIAL java/util/ArrayList.<init> ()V
ASTORE 2

示例2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 /**
* 约定泛型的list,可以通过反射成功添加 int类型数据进去,通过反射可以正常读取,直接读取时会提示类型转化异常。
*/
@Test
public void typeErasure() {
try {
List<String> strList = new ArrayList();
strList.getClass().getMethod("add", Object.class).invoke(strList, 123);
System.out.println("strList'size :" + strList.size());
System.out.println(strList.getClass().getMethod("get", int.class).invoke(strList, 0));
System.out.println(strList.get(Integer.valueOf(0)));
} catch (Exception e) {
e.printStackTrace();
}
}

示例3

1
2
3
4
泛型针对引用有效。
List<String> strList1 = new ArrayList();//有效果(阿里巴巴规范也提倡这么写)
List<String> strList2 = new ArrayList<String>();//效果同上面
List strList3 = new ArrayList<String>();//无效果

由于 泛型仅仅生存到编译时期,所以称之为 伪泛型。

多态的冲突

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
abstract class Math<T> {
abstract T max(T t1, T t2);
}
-------二进制码---------
abstract max(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

class IntMath extends Math<Integer> {

@Override
Integer max(Integer t1, Integer t2) {
return java.lang.Math.max(t1, t2);
}
}
--------二进制码--------
max(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;
synthetic bridge max(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
L0
LINENUMBER 28 L0
ALOAD 0
ALOAD 1
CHECKCAST java/lang/Integer
ALOAD 2
CHECKCAST java/lang/Integer
INVOKEVIRTUAL com/hardydou/jmm/IntMath.max (Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;
ARETURN

泛型子类重写不是简单的重写,而是重载+重写

实战

基本类型不可以作为泛型

List<int> list;//编译不通过

泛型不可以被实例化

1
2
3
4
class A<T> {
T t=new T();//不可以被直接实例化
.......
}

泛型使用instanceOf

1
2
3
4
5
6
7
List<String> list1 = new ArrayList<>();
//可以
boolean s1 = (list1 instanceof ArrayList<?>);
boolean s3 = (list1 instanceof ArrayList);
//编译报错
boolean s2 = (list1 instanceof ArrayList<String>);