Guice TypeLiteral实现学习(Java匿名内部类泛型编译巧合)

Guice TypeLiteral研究

Guice对绑定泛型的类使用了一个小技巧。那就是通过TypeLiteral利用Java匿名内部类来获取绑定具体的Runtime时候的类型参数信息。

一段取类型参数的代码来自于:TypeLiteral.java line 98

/**
* Returns the type from super class's type parameter in {@link MoreTypes#canonicalize(Type)
* canonical form}.
*/
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return canonicalize(parameterized.getActualTypeArguments()[0]);
}


代码很简单,主要目的就是从Class的genericSuperClass里面取类型参数信息。Java泛型的实现是runtime“擦除”式的,也就是在runtime的时候泛型的类已经是“固定”的。Class的信息并不会根据实例的信息而变化。以Map<K,V>为例子,编译好后的Map.class包含两个类型参数信息,一个是K,一个是V.

假设两个Map实例:

Map<Integer,String> a = new HashMap<Integer,String>();
Map<Key,Object> b = new HashMap<Key,Object>()


在Runtime的时候a,b都是同一个Map class的不同实例而已。类型参数在Runtime的时候已经不存在。通过a.class得到的Class里面不会包含任何具体如Integer,String的类型参数的信息。

要想获得一个泛型类的某个实例的具体参数类型信息,一个途径就是让某个实例的class被编译的时候就将具体的类型参数编译进去。 然后将这个class跟某个具体实例关联起来,以间接达到存储类型信息的效果。 Java的匿名内部类刚刚有这个效果。

例子:
假设有一个Test.java

public class Test<K, V> {
protected Test() {
}
}


这个被编译的具体的Test.class文件只会包办K,V两个类型参数,不具备实际意义。而下面这种写法就不一样

Test<String,Integer> test = new Test<String, Integer>() {};

代码在被编译的时候会编译一个Test的子类的匿名内部类。这个匿名内部类在编译的时候会将java.lang.String和Integer作为类型参数编译到class中去。这样通过探索test.class就可以取得他的类型参数是String和Integer。

匿名内部类的这样的实现,刚刚符合Guice此处的需求。于是就有了Guice中这样的用法

bind(new TypeLietral()<List<String>>{}).annotationWith(Named.names("Language")).to(new ArrayList<String>());
.

[color=red]Java的匿名内部类对泛型的编译的方式被用在Guice中,不知道是无心插柳还是刻意为之? 呵呵[/color]

附带一个试验类:



import java.lang.reflect.ParameterizedType;

public class ExploreGenericType {

public static void main(String[] args) {
// exloreClass(ExploreGenericType.class);
Type type = exploreObject(new Test<String, Integer>() {
});
Type type2 = exploreObject(new TestChild<String, Integer>());
Type type3 = exploreObject(new TestStringInteger<String, Integer>());
if (type.equals(type2)) {
System.out.println("Their generic super class is same one.");
} else {
System.out.println("Their generic super class is not same one.");
}

// System.out.println(ArrayList.class.getGenericSuperclass());
}

private static Type exploreObject(Object object) {
System.out.println("Explore Object : " + object);
exloreClass(object.getClass());
return object.getClass().getGenericSuperclass();

}

private static void exloreClass(Class klass) {
System.out.println("Explore class : " + klass.getCanonicalName());
System.out.println((klass instanceof Type));

Type genericType = klass.getGenericSuperclass();
System.out.println(String.format("Class %s generic superclass is %s",
klass, genericType));
System.out.println(String.format("Generic type is a %s", genericType));
if (genericType instanceof Class) {
System.out.println("Generic is a Object.");
return;
}
ParameterizedType parameterized = (ParameterizedType) genericType;
System.out.println(String.format("%s parameterized Class is %s",
parameterized, parameterized.getActualTypeArguments()));

System.out.println(String.format("%s parameterized OwnerType is %s",
parameterized, parameterized.getOwnerType()));

System.out.println(String.format("%s parameterized RawType is %s",
parameterized, parameterized.getRawType()));

Type[] types = parameterized.getActualTypeArguments();

for (Type type : types) {
if (type instanceof TypeVariable) {
TypeVariable var = (TypeVariable) type;
System.out.println("Type Name is :" + var.getName());
System.out.println("Type GenericDeclaration is :"
+ var.getGenericDeclaration());
}
}
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值