mybatis中有许多精巧的代码,现分析其中一个TypeReference来学习一下。
其代码路径为:
org.apache.ibatis.type.TypeReference<T>
参考jar文件:mybatis-3.4.5.jar
完整代码为:
/**
* Copyright 2009-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.type;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* References a generic type.
*
* @param <T> the referenced type
* @since 3.1.0
* @author Simone Tripodi
*/
public abstract class TypeReference<T> {
private final Type rawType;
protected TypeReference() {
rawType = getSuperclassTypeParameter(getClass());
}
Type getSuperclassTypeParameter(Class<?> clazz) {
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof Class) {
// try to climb up the hierarchy until meet something useful
if (TypeReference.class != genericSuperclass) {
return getSuperclassTypeParameter(clazz.getSuperclass());
}
throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
+ "Remove the extension or add a type parameter to it.");
}
Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
// TODO remove this when Reflector is fixed to return Types
if (rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType) rawType).getRawType();
}
return rawType;
}
public final Type getRawType() {
return rawType;
}
@Override
public String toString() {
return rawType.toString();
}
}
编写测试类:
import org.apache.ibatis.type.TypeReference;
public class TestTypeReference {
public static void main(String[] args) {
TypeReference<String> typeReference = new TypeReference<String>() {
};
System.out.println(typeReference.getRawType());
}
}
以上测试类输出结果为:class java.lang.String
TypeReference在这里必须被实例化之后,才能够被读取到泛型的内容,他本身被定义为abstract抽象的,又因为他并没有抽象方法,所以在new的时候需要加空花括号,表示实例化一个抽象类的匿名实现类实例。
其实,主体的逻辑就都在构造方法里了,rawType = getSuperclassTypeParameter(getClass()); 这一句代码完成了泛型的读取。
下面边调试边分析他的解析过程:
可以看到,当前类(也就是咱们的匿名TypeReference实现类)的名字是TypeREfrence$1,那么他的父类一定是TypeReference,这里面有一个递归处理:
也就是只要父类是TypeReference即可,至于是几层继承,没关系。但当最后也没找到TypeReference这个非Class类型的class时,就报错。
跟踪调试,genericSuperclass的值的getClass()结果是:
()sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl,其实这里得到的superClass就是TypeReference而已,而TypeReference被定义为泛型的,所以他的class对象具体类型是ParameterizedTypeImpl,他不是一个Class的instance,而是ParameterizedType接口的一个实例。
然后就调用 ParameterizedType#getActualTypeArguments()这个方法获取到泛型数组,即可读取到泛型结果了。
这个类的应用场景,比如想要传递Map<String,Object>这样一个类型信息,我们无法Map<String,Object>.class的方式传递,此时我们可以通过 new TypeReference<Map<String,Object>(){}对象传递获取:
TypeReference<Map<String,Object>> typeReference = new TypeReference<Map<String,Object>>() {
};
System.out.println(typeReference.getRawType());
Type genericSuperclass = typeReference.getClass().getGenericSuperclass();
Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0]; // Map<String,Object>
System.out.println(((ParameterizedType)rawType).getActualTypeArguments()[0]); // String
System.out.println(((ParameterizedType)rawType).getActualTypeArguments()[1]); // Object
是不是挺好用的?
特别需要注意的是,test2这个例子中,直接typeReference.getRawType()返回的是interface java.util.Map,是不带泛型信息的。