Last active
February 22, 2016 12:54
-
-
Save winteryoung/e5947f13967e2f3166e7 to your computer and use it in GitHub Desktop.
java 泛型类型推导
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 输出 Integer | |
// 用法: GenericActualArgumentResolver.resolve(A.class, C.class, 0); | |
import com.google.common.collect.Lists; | |
import javax.annotation.Nonnull; | |
import javax.annotation.Nullable; | |
import java.lang.reflect.ParameterizedType; | |
import java.lang.reflect.Type; | |
import java.lang.reflect.TypeVariable; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.List; | |
/** | |
* 泛型参数实参类型解析器。 | |
* 示例: | |
* <pre> | |
class A[T] extends B[T, Integer] { } | |
GenericActualArgumentResolver.resolve(A.class, B.class, 1); ==> 输出 java.lang.Integer | |
* </pre> | |
* | |
* @author fanshen | |
* @since 14-2-12 | |
*/ | |
public class GenericActualArgumentResolver { | |
private GenericActualArgumentResolver() { } | |
/** | |
* 泛型参数信息模型。 | |
*/ | |
private static class ParamTypeInfo { | |
/** | |
* 当前类上声明的泛型类型。 | |
*/ | |
private List<String> declaredTypes; | |
/** | |
* 向当前类的父类上应用的泛型类型。 | |
*/ | |
private List<String> appliedTypes; | |
private ParamTypeInfo(List<String> declaredTypes, List<String> appliedTypes) { | |
this.declaredTypes = declaredTypes; | |
this.appliedTypes = appliedTypes; | |
} | |
} | |
private static String resolveSuperGenericTypeParam(@Nullable Class klass, | |
@Nonnull Class superTypeThatDeclaresFormalTypeParam, | |
int typeParamIndex, | |
@Nonnull List<ParamTypeInfo> paramTypeInfoList) { | |
if (klass == null) { | |
return null; | |
} | |
Collection<ParameterizedType> genericSuperTypes = getGenericSuperTypes(klass); | |
addParamInfo(paramTypeInfoList, klass, genericSuperTypes); | |
for (ParameterizedType genericSuperType : genericSuperTypes) { | |
Class rawType = (Class) genericSuperType.getRawType(); | |
if (rawType == superTypeThatDeclaresFormalTypeParam) { | |
return deductParam(paramTypeInfoList, typeParamIndex); | |
} | |
} | |
return resolveSuperGenericTypeParam(klass.getSuperclass(), | |
superTypeThatDeclaresFormalTypeParam, | |
typeParamIndex, | |
paramTypeInfoList); | |
} | |
private static void addParamInfo(List<ParamTypeInfo> paramTypeInfoList, | |
Class klass, | |
Collection<ParameterizedType> genericSuperTypes) { | |
List<String> declaredTypes = calcDeclaredTypes(klass); | |
List<String> appliedTypes = calcAppliedTypes(genericSuperTypes); | |
ParamTypeInfo paramTypeInfo = new ParamTypeInfo(declaredTypes, appliedTypes); | |
paramTypeInfoList.add(paramTypeInfo); | |
} | |
private static List<String> calcAppliedTypes(Collection<ParameterizedType> genericSuperTypes) { | |
List<String> appliedTypes = Lists.newArrayList(); | |
for (ParameterizedType genericSuperType : genericSuperTypes) { | |
Type[] actualTypeArguments = genericSuperType.getActualTypeArguments(); | |
String fqName; | |
for (Type actualTypeArgument : actualTypeArguments) { | |
if ((actualTypeArgument instanceof TypeVariable)) { | |
TypeVariable typeVariable = (TypeVariable) actualTypeArgument; | |
fqName = typeVariable.getName(); | |
} else if (actualTypeArgument instanceof ParameterizedType) { | |
ParameterizedType parameterizedType = (ParameterizedType) actualTypeArgument; | |
Class rawType = (Class) parameterizedType.getRawType(); | |
fqName = rawType.getName(); | |
} else if (actualTypeArgument instanceof Class) { | |
Class typeArgClass = (Class) actualTypeArgument; | |
fqName = typeArgClass.getName(); | |
} else { | |
fqName = ""; | |
} | |
if (fqName == null) { | |
fqName = ""; | |
} | |
int index = fqName.indexOf(" "); | |
if (index < 0) { | |
index = fqName.indexOf("\t"); | |
} | |
if (index > 0) { | |
fqName = fqName.substring(0, index); | |
} | |
appliedTypes.add(fqName); | |
} | |
} | |
return appliedTypes; | |
} | |
private static List<String> calcDeclaredTypes(Class klass) { | |
List<String> declaredTypes = Lists.newArrayList(); | |
{ | |
TypeVariable[] typeParameters = klass.getTypeParameters(); | |
for (TypeVariable typeParameter : typeParameters) { | |
String fqName = typeParameter.getName(); | |
if (fqName == null) { | |
fqName = ""; | |
} | |
int index = fqName.indexOf(" "); | |
if (index < 0) { | |
index = fqName.indexOf("\t"); | |
} | |
if (index > 0) { | |
fqName = fqName.substring(0, index); | |
} | |
declaredTypes.add(fqName); | |
} | |
} | |
return declaredTypes; | |
} | |
private static Collection<ParameterizedType> getGenericSuperTypes(Class klass) { | |
List<Type> superTypes = Lists.newArrayList(); | |
List<ParameterizedType> genericSuperTypes = Lists.newArrayList(); | |
Type genericSuperclass = klass.getGenericSuperclass(); | |
if (genericSuperclass != null) { | |
superTypes.add(genericSuperclass); | |
} | |
Type[] genericInterfaces = klass.getGenericInterfaces(); | |
if (genericInterfaces != null) { | |
Collections.addAll(superTypes, genericInterfaces); | |
} | |
for (Type superType : superTypes) { | |
if (!(superType instanceof ParameterizedType)) { | |
continue; | |
} | |
ParameterizedType parameterizedType = (ParameterizedType) superType; | |
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); | |
if (actualTypeArguments == null || actualTypeArguments.length <= 0) { | |
continue; | |
} | |
genericSuperTypes.add(parameterizedType); | |
} | |
return genericSuperTypes; | |
} | |
private static String deductParam(List<ParamTypeInfo> paramTypeInfoList, int typeParamIndex) { | |
if (paramTypeInfoList.size() <= 0) { | |
return null; | |
} | |
String targetType = null; | |
int declaredTypeIndex = -1; | |
for (int i = paramTypeInfoList.size() - 1; i >= 0; i--) { | |
ParamTypeInfo paramTypeInfo = paramTypeInfoList.get(i); | |
List<String> declaredTypes = paramTypeInfo.declaredTypes; | |
List<String> appliedTypes = paramTypeInfo.appliedTypes; | |
if (declaredTypeIndex < 0) { | |
targetType = appliedTypes.get(typeParamIndex); | |
} else { | |
targetType = appliedTypes.get(declaredTypeIndex); | |
} | |
boolean found = false; | |
for (int j = 0; j < declaredTypes.size(); j++) { | |
String declaredType = declaredTypes.get(j); | |
if (declaredType.equals(targetType)) { | |
declaredTypeIndex = j; | |
found = true; | |
break; | |
} | |
} | |
// 没有找到声明的参数说明应用的参数不是泛型变量,可以直接给出结果 | |
if (!found) { | |
return targetType; | |
} | |
} | |
if (targetType == null) { | |
return null; | |
} | |
return targetType; | |
} | |
/** | |
* 解析。 | |
* | |
* @param klass 含有泛型实参信息的类型 | |
* @param superTypeThatDeclaresFormalTypeParam 含有泛型形参信息的基类类型 | |
* @param typeParamIndex 泛型参数在 superTypeThatDeclaresFormalTypeParam 中的索引(0起) | |
*/ | |
public static String resolve(@Nonnull Class klass, | |
@Nonnull Class superTypeThatDeclaresFormalTypeParam, | |
int typeParamIndex) { | |
return resolveSuperGenericTypeParam(klass, | |
superTypeThatDeclaresFormalTypeParam, | |
typeParamIndex, | |
Lists.<ParamTypeInfo>newArrayList()); | |
} | |
/** | |
* 解析。 | |
* | |
* @param klass 含有泛型实参信息的类型 | |
* @param superTypeThatDeclaresFormalTypeParam 含有泛型形参信息的基类类型 | |
* @param typeParamIndex 泛型参数在 superTypeThatDeclaresFormalTypeParam 中的索引(0起) | |
*/ | |
public static Class<?> resolveToClass(@Nonnull Class klass, | |
@Nonnull Class superTypeThatDeclaresFormalTypeParam, | |
int typeParamIndex) { | |
String typeName = resolve(klass, superTypeThatDeclaresFormalTypeParam, typeParamIndex); | |
if (typeName == null) { | |
return null; | |
} | |
Class<?> extensionClass; | |
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); | |
try { | |
extensionClass = contextClassLoader.loadClass(typeName); | |
} catch (ClassNotFoundException e) { | |
throw new RuntimeException("无法加载类:" + typeName, e); | |
} | |
return extensionClass; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment