`
liusu
  • 浏览: 170061 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

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

    博客分类:
  • 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>());
.

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

附带一个试验类:


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());
			}
		}
	}
}










分享到:
评论
4 楼 liusu 2009-06-16  
恩。。 刚刚试验了一下。。。 其实这还是保存在编译时候的“字面量”(这个词不晓得合适不合适)。

public class SomeObjectImpl extends SomeObject<String, String> { 


泛型的字面量刚刚好是String,String而不是K,V,所以正确取得了。

谢了 :)
3 楼 taowen 2009-06-15  
public class SomeObject {
  public Map<String, String> someField;
}

SomeObject.class.getField("someField").getGenericType();

但是如果是这样的话
public class SomeObject<K,V> {
  public Map<K, V> someField;
}
public class SomeObjectImpl extends SomeObject<String, String> {
}

对SomeObjectIml取someField的genericType就得不到String和String。这个时候我们就要利用TypeLiteral了:
TypeLiteral.get(SomeObject.class).getFieldType(SomeObject.class.getField("someField"));

这样就可以得到Field的genericType,而且能得到正确的type argument。
2 楼 liusu 2009-06-08  
1、继承时指定的泛型参数

Map<K,V>可以得到泛型参数,但是其值为K和V。

你说得具体是哪一种情形? 除了匿名内部类得方式外,能不能再给我举个例子在何种情况下可以得到具体得泛型参数类型信息的。

1 楼 taowen 2009-06-08  
其实原理很简单啦。Java只会在两个场景下保留泛型信息:1、继承时指定的泛型参数。2、Field上指定的泛型参数。第一种需要用getGenericSuperClass第二种需要用getGenericFieldType。普通的泛型参数用ParameterizedType就可以拿到了

相关推荐

    guice入门学习资料

    guice 学习资料,快速掌握guice的编程技巧以及了解其机制。

    Java on Guice

    Does this sound like you? • "My application is easy to unit-test!" • "I don't worry about Dependency Bloat!" • "My code is clean! It has high signal-to-noise!" • "My tests never mysteriously fail ...

    Google Guice: Agile Lightweight Dependency Injection Framework

    Guice (pronounced "Juice") is the 100% Java icing on the cake of Java dependency injection. Unlike other popular DI frameworks such as Spring, Guice fully embraces modern Java language features and ...

    guice.jar/guice.jar

    guice.jar guice.jar guice.jar guice.jar guice.jar guice.jar guice.jar

    reportNG支持中文及饼状图_包含guice、velocity和java-client

    该资源中包含如下jar包: reportng-1.1.4.jar(这个jar包是经过修改的,支持中文以及饼状图,贼好用) velocity-dep-1.4.jar java-client-2.1.0.jar guice-3.0.jar 使用方式请查看我的个人博客

    google guice基础例子

    Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC)。Guice非常小而且快。Guice是类型安全的,它能够对构造函数,属性,方法(包含任意个参数的任意方法,而不仅仅是setter...

    Java guice3.0轻量级的依赖注入框架 组件

    Java guice3.0轻量级的依赖注入框架 组件guice 是轻量级的依赖注入框架,依赖注入是类将他们的依赖声明为参数,而不是直接创建依赖的一种设计模式。

    java面试笔试题库java学习笔记开发教程互联网公司面试资料大全合集.zip

    java面试笔试题库java学习比较开发教程互联网公司面试资料大全合集: 100家大公司java笔试题汇总.doc 125条常见的java 面试笔试题大汇总.pdf 2011最新整理java经典代码.doc 25个经典的Spring面试问答.docx 8张图解...

    guice-3.0-API文档-中英对照版.zip

    标签:google、inject、guice、jar包、java、API文档、中英对照版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准...

    Google Guice与MyBatis集成,并实现发送邮件轮询

    Google Guice 这个高效的与Spring类似的依赖注入框架; MyBatis配置和使用; Google Guice与MyBatis集成,支持注解事务,简单的无法想象; Mybatis与mysql集成;实现发送邮件轮询; 源码是个web项目,里面有数据库的...

    guice-3.0-API文档-中文版.zip

    标签:google、inject、guice、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请...

    guice超轻量级依赖注入

    guice超轻量级依赖注入用了才知道是爽

    google guice 3.0源码

    google guice 3.0源码,官方下载,帮助你更好理解google guice实现的原理

    guice-multibindings-3.0-API文档-中文版.zip

    标签:google、inject、extensions、guice、multibindings、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变...

    guice-assistedinject-3.0-API文档-中英对照版.zip

    标签:extensions、google、assistedinject、inject、guice、jar包、java、API文档、中英对照版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和...

    Guice用户中文指南

    Guice用户中文指南,Guice (读作"juice")是超轻量级的,下一代的,为Java 5及后续版本设计的依赖注入容器

    Java依赖注入框架Guice2

    Guice2中最轻的API扩展将极大地影响开发者代码的大小和维护。Guice2的开发者很好地平衡了可维护性和敏捷性。

    google Guice 1.0 用户指南 中文

    用 Guice 写 Java Guice 1.0 用户指南 王咏刚 译 Guice (读作"juice")是超轻量级的,下一代的,为Java 5及后续版本设计的依赖注入容器。

    java面试笔试资料java笔试题大集合及答案题库java笔试题汇总资料188个合集.zip

    依赖注入与JSR-330的参考实现——Guice.docx 关于Java框架Vert.x的几点思考.docx 关于堆和栈的那些事.docx 写好Java代码的30条经验总结.docx 华为java笔试面试题2014.doc 多态的理解.docx 大公司最喜欢问的Java集合...

Global site tag (gtag.js) - Google Analytics