前面说了,rentrunType和responseType都是通过反射拿到的,但是范型在编译的时候不是会被擦除吗?那又是怎么拿到具体的类型的?
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//获取返回值的类型
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
在进入DefaultCallAdapterFactory里看看
@Override public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
//这里根据returnType获取到里面的参数化类型的type
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return executor == null
? call
: new ExecutorCallbackCall<>(executor, call);
}
};
}
好,再回到获取returnType的那一行Type returnType = method.getGenericReturnType();
public Type getGenericReturnType() {
//如果有签名信息,则根据签名信息获取
if (getGenericSignature() != null) {
return getGenericInfo().getReturnType();
} else { return getReturnType();}
}
这个签名信息实质上是编译成字节码后jvm加上的,看下面的例子
public class Test {
public static void main(String[] args) {
test();
}
public static List<Map<String, Integer>> test(){
System.out.println("hello!");
return null;
}
}
来查看test的字节码,看到那个signature后面附带的信息没,所指的便是这个
// access flags 0x9
// signature ()Ljava/util/List<Ljava/util/Map<Ljava/lang/String;Ljava/lang/Integer;>;>;
// declaration: java.util.List<java.util.Map<java.lang.String, java.lang.Integer>> test()
public static test()Ljava/util/List;
L0
LINENUMBER 13 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "hello!"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 14 L1
ACONST_NULL
ARETURN
MAXSTACK = 2
MAXLOCALS = 0
下面来看个示例
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
test();
//获取Test类中的test方法
Method method = Test.class.getDeclaredMethod("test");
//获取返回值类型
Type type = method.getGenericReturnType();
//通过递归取出来
checkType(type);
//由于没有传入参数,下面先注释掉
/*for (Type genericParamType : method.getGenericParameterTypes()) {
checkType(genericParamType);
}*/
//这里获取signature字段
Field signature = Method.class.getDeclaredField("signature");
signature.setAccessible(true);
System.out.println("signature : " + signature.get(method));
}
public static List<Map<String, Integer>> test(){
System.out.println("hello!");
return null;
}
public static void checkType(Type type) {
//如果是参数化类型
if (type instanceof ParameterizedType) {
System.out.println("ParameterizedType : " + type);
for (Type type1 : ((ParameterizedType) type).getActualTypeArguments()) {
checkType(type1);
}
} else {
System.out.println("Type : " + type);
}
}
输出为
hello!
ParameterizedType : java.util.List<java.util.Map<java.lang.String, java.lang.Integer>>
ParameterizedType : java.util.Map<java.lang.String, java.lang.Integer>
Type : class java.lang.String
Type : class java.lang.Integer
signature : ()Ljava/util/List<Ljava/util/Map<Ljava/lang/String;Ljava/lang/Integer;>;>;
当然这个方法也是有限制的,首先是signature 不能去掉,一般也是在混淆的时候会去掉,所得保留即可。