关于 TypeReference {} 大括号的问题引发的泛型思考

基础比较差。
本篇文章,仅属于个人理解。
不对,请指出 ^_^

TypeReference

下面只是我的初步疑问,下面会继续分析。

我只是在想:为什么使用的时候,非要加一个 {} 大括号呢???不加 {} 难道不香吗??

下面有三种:
1、fastjson:protected 构造器(不能直接 new 对象,但子类可以访问这个构造器,我们可以创建匿名内部类来解决,也就是new 对象后面加上 {} 大括号。)
2、hutool:虽然构造器是 public,但是类是抽象的,你没法使用,必须要进行实现,即使这个抽象类没有 abstract 方法。所以,要使用匿名内部类来进行实现,也需要加 {} 大括号。
3、jackson:它把上面二者都给结合了。

这个问题先按下不表,后面进行讨论具体原因,我们先看看泛型。

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
26
// 2022-02-11 11:25 关于 new TypeReference<T> 需要加 {} 大括号的问题 ===> 因为泛型问题
public static void main(String[] args) throws Exception {
// 构造器是 protected 类型,所以,我们只能创建一个匿名内部类,所以要加 {}
com.alibaba.fastjson.TypeReference<List<String>> listTypeReference = new com.alibaba.fastjson.TypeReference<List<String>>() {
};

// 这个类是 abstract 修饰,所以,我们只能创建一个匿名内部类,所以要加 {}
cn.hutool.core.lang.TypeReference<List<String>> x = new cn.hutool.core.lang.TypeReference<List<String>>() {
};


// 要想不用 {},需要自己创建一个类来继承(但是这样使用会出问题的)
class MyTypeRef<T> extends com.alibaba.fastjson.TypeReference<T> {
}
MyTypeRef<List<String>> myTypeRef = new MyTypeRef<>();
MyTypeRef<List<String>> myTypeRef1 = new MyTypeRef<>();

// 加 {} 也不报错 ===> 匿名内部类(但是这样使用会出问题的)
MyTypeRef<List<String>> myTypeRef2 = new MyTypeRef<List<String>>() {
};

// myTypeRef.getClass() = {Class@785} "class com.taopanfeng.junit.MyTest$1MyTypeRef"
// myTypeRef1.getClass() = {Class@785} "class com.taopanfeng.junit.MyTest$1MyTypeRef"
// myTypeRef2.getClass() = {Class@786} "class com.taopanfeng.junit.MyTest$3"

}

在这里插入图片描述

Jackson注释的启发

它上面说,是受到了文章 Super Type Tokens — Neal Gafter’s blog

简直一毛一样,O(∩_∩)O哈哈~

在这里插入图片描述

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
26
// 使用  Java 泛型规范 Type 类型,来保存住泛型。

// [0] 我们要知道,Class<T> 就是泛型,实现了 Type 接口。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {

// [1] 获取 超类
Type superClass = getClass().getGenericSuperclass();

// [2] 如果超类 为 Class 本身,报错
if (superClass instanceof Class<?>) { // sanity check, should never happen
throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
}

// [3] 转为 参数化泛型,获取第一个泛型参数类型
// TypeReference<T> ===> getActualTypeArguments() 返回数组长度 1
// TypeReference<T,S> ===> getActualTypeArguments() 返回数组长度 2
// 所以这里 getActualTypeArguments()[0] 是获取泛型 T
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];


============================================

以上什么意思:看下图

在这里插入图片描述

泛型

可参考 Java基础总结 — 泛型
也可查看这个视频 05.泛型的擦除和补偿

下面引用这个视频的一个截图:
在这里插入图片描述

泛型的出现是 JDK 1.5。
原本 JVM 全做了就好了,就是为了和以前的兼容,提供了几个方法,类,接口。

重点参考方法 :
在这里插入图片描述
在这里插入图片描述

注释翻译

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
// 泛型标志处理
private native String getGenericSignature0();

// 泛型信息库;懒加载
private volatile transient ClassRepository genericInfo;

// 泛型工厂访问器
private GenericsFactory getFactory() {
// 创建作用范围 和 工厂
// 核心反射工厂.制作(泛型声明, 类范围)
return CoreReflectionFactory.make(this, ClassScope.make(this));
}

// 泛型信息库访问器;
// 泛型信息是懒加载的
private ClassRepository getGenericInfo() {
ClassRepository genericInfo = this.genericInfo;

// 默认:第一次进入,当前 Class 的泛型信息为空
// 获取泛型签名信息
// 生成泛型信息,并放入泛型
if (genericInfo == null) {
String signature = getGenericSignature0();
if (signature == null) {
genericInfo = ClassRepository.NONE;
} else {
genericInfo = ClassRepository.make(signature, getFactory());
}
this.genericInfo = genericInfo;
}
return (genericInfo != ClassRepository.NONE) ? genericInfo : null;
}


// 返回代表此 {@code Class} 表示的实体(类、接口、原始类型或 void)的直接超类的 {@code Type}。
// <p>如果超类是参数化类型,则返回的 {@code Type} 对象必须准确反映源代码中使用的实际类型参数。
// 如果之前没有创建过表示超类的参数化类型,则会创建它。
// 有关参数化类型的创建过程的语义,请参见 {@link java.lang.reflect.ParameterizedType ParameterizedType} 的声明。
// 如果此 {@code Class} 表示 {@code Object} 类、接口、原始类型或 void,则返回 null。
// 如果此对象表示一个数组类,则返回表示 {@code Object} 类的 {@code Class} 对象。
// @throws java.lang.reflect.GenericSignatureFormatError
// 如果泛型类签名不符合 <cite>Java™ 虚拟机规范<cite> 中指定的格式
// @throws TypeNotPresentException 如果泛型超类引用不存在的类型声明
// @如果泛型超类引用了由于任何原因无法实例化的参数化类型,则抛出 java.lang.reflect.MalformedParameterizedTypeException
// @return 此对象表示的类的超类
// @since 1.5
public Type getGenericSuperclass() {
ClassRepository info = getGenericInfo();
if (info == null) {
return getSuperclass();
}

// 历史异常:通用签名将接口标记为超类 = 对象,但此 API 为接口返回 null
if (isInterface()) {
return null;
}

return info.getSuperclass();
}


// 返回表示由该对象表示的类或接口直接实现的接口的 {@code Type}。
// <p>如果超接口是参数化类型,则为其返回的 {@code Type} 对象必须准确反映源代码中使用的实际类型参数。
// 如果之前没有创建过代表每个超接口的参数化类型,则创建它。
// 有关参数化类型的创建过程的语义,请参见 {@link java.lang.reflect.ParameterizedType ParameterizedType} 的声明。
// <p> 如果此对象表示一个类,则返回值是一个数组,其中包含表示该类实现的所有接口的对象。
// 数组中接口对象的顺序对应于该对象所代表的类声明的{@code implements}子句中接口名称的顺序。
// 对于数组类,接口 {@code Cloneable} 和 {@code Serializable} 按该顺序返回。
// <p>如果此对象表示一个接口,则该数组包含表示该接口直接扩展的所有接口的对象。
// 数组中接口对象的顺序对应于该对象表示的接口声明的 {@code extends} 子句中接口名称的顺序。
// <p>如果该对象表示一个没有实现接口的类或接口,则该方法返回一个长度为 0 的数组。
// <p>如果该对象表示一个原始类型或 void,该方法返回一个长度为 0 的数组。
// @throws java .lang.reflect.GenericSignatureFormatError
如果泛型类签名不符合 <cite>Java™ 虚拟机规范<cite> 中指定的格式,则 @throws TypeNotPresentException 如果任何泛型超接口引用了不存在的类型声明
// @throws java.lang.reflect.MalformedParameterizedTypeException
如果任何通用超接口引用了由于任何原因无法实例化的参数化类型
// @return 由此类实现的接口数组
// @since 1.5
public Type[] getGenericInterfaces() {
ClassRepository info = getGenericInfo();
return (info == null) ? getInterfaces() : info.getSuperInterfaces();
}

}

原理

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
26
27
28
29
30
31
32
// 2022-02-11 17:39 反射 Class#getGenericSignature0 方法
public static void main(String[] args) throws Exception {
class MyRef<T> extends TypeReference<T> {
}

Class<? extends TypeReference<List<Student>>> class1 = new TypeReference<List<Student>>() {}.getClass();
Class<? extends MyRef> class2 = new MyRef<List<Student>>().getClass();
Class<? extends MyRef<List<Student>>> class3 = new MyRef<List<Student>>() {}.getClass();
Class<? extends ArrayList> class4 = new ArrayList<Student>().getClass();
Class<? extends ArrayList<Student>> class5 = new ArrayList<Student>() {}.getClass();
ArrayList<Student> s1 = new ArrayList<Student>();
ArrayList<Student> s2 = new ArrayList<Student>() {};
Class<? extends ArrayList> c1 = s1.getClass();
Class<? extends ArrayList> c2 = s2.getClass();

Method getGenericSignature0 = Class.class.getDeclaredMethod("getGenericSignature0");
getGenericSignature0.setAccessible(true);
String invoke1 = (String) getGenericSignature0.invoke(class1);
// Lcom/alibaba/fastjson/TypeReference<Ljava/util/List<Lcom/taopanfeng/fastson/MyTest$Student;>;>;

String invoke2 = (String) getGenericSignature0.invoke(class2);
// <T:Ljava/lang/Object;>Lcom/alibaba/fastjson/TypeReference<TT;>;

String invoke3 = (String) getGenericSignature0.invoke(class3);
// Lcom/taopanfeng/fastson/MyTest$1MyRef<Ljava/util/List<Lcom/taopanfeng/fastson/MyTest$Student;>;>;

String invoke4 = (String) getGenericSignature0.invoke(class4);
// <E:Ljava/lang/Object;>Ljava/util/AbstractList<TE;>;Ljava/util/List<TE;>;Ljava/util/RandomAccess;Ljava/lang/Cloneable;Ljava/io/Serializable;

String invoke5 = (String) getGenericSignature0.invoke(class5);
// Ljava/util/ArrayList<Lcom/taopanfeng/fastson/MyTest$Student;>;
}

在这里插入图片描述

在这里插入图片描述