在java中使用TypeLiteral

时间:2011-12-28 12:27:52

标签: java java-ee guice

请提供一些基本信息,了解如何使用Google Guice或Java EE TypeLiteral。如果使用简单的代码解释它将会非常有用,提前感谢

5 个答案:

答案 0 :(得分:16)

Guice中TypeLiteral的目的是允许您将类和实例绑定到泛型类型(指定类型参数),避免因泛型不是用Java实现的事实,即事实该擦除在运行时隐藏了SomeInterface<String>SomeInterface<Integer>之间的差异。 TypeLiteral通过创建泛型类型的 ad hoc 子类,允许通用参数的值继续擦除。

TypeLiteral的使用示例:

bind(new TypeLiteral<SomeInterface<String>>(){})
    .to(SomeImplementation.class);

这会将SomeInterface<String>类型的参数绑定到SomeImplementation类。

对于某些背景信息,请查看超级类型令牌上的this blog post和类型文字上的then this one

答案 1 :(得分:4)

与Guice中的任何内容一样 - 模块化,可重用性和删除样板是所有实用程序的核心概念。

当然,你在Guice中所做的任何事情都可以用Java来模仿 - 代价是大量的样板......所以真正的问题是:

我们如何使用TypeLiterals编写更多模块化/可重用组件?

Guice中TypeLiterals的强大之处在于它允许您在不定义服务内容的情况下引用服务的实现。

让我们从程序中的一个简单列表开始,我们有许多类型的列表,这些列表的处理方式不同:

List<String> myStringList = new ArrayList<String>();

现在,我该如何处理这些字符串?在运行时,没有办法“知道”它的String列表。所以,我经常会创建一个像我这样的工厂,为我获取处理对象:

ProcessorFactory.get(String.class).process(myStringList); 

因此,我可能会使用工厂(带有一堆if / else或case语句)来为不同的数据类型定义处理器。我的构造函数,对于使用这些处理器的对象,需要访问各种处理器实现,可能如下所示:

public MyClass(Processor<String> strProcessor, Processor<Integer> intProcessor)P
{
    //Simple enough, but alot of boiler plate is required to launch this constructor.
}

//and to invoke 
new MyClass(PRocessorFactory.get(....), ProcessorFactory.get(...)); 

到目前为止一切都很好......直到我们意识到有更好的方法:

在Guice世界中,我可以忘记编写这个工厂 - 相反,我可以将类明确地绑定到处理器。这样做的好处是没有静态依赖 - 需要使用处理器实现的类不需要对工厂进行任何静态依赖,而是直接注入类。因此,我可以轻松地定义一个使用复杂依赖关系的类,而不必构建一个工厂感知的类构建器......因此,我的样板少得多:

@Inject
public MyClass(Processor<String> implStr, Processor<Integer> implInt)
{
   //Now , this method will work magically, because Guice is capable of  
   //Using the loaded modules, which define bindings between generics and their implementations
}

//Elsewhere I simply define a single guice module that does the binding, and make sure to load it before my application launches. 

关于接口实现和绑定示例,有一个很好的教程,在这里:http://thejavablog.wordpress.com/2008/11/17/how-to-inject-a-generic-interface-using-guice/

答案 2 :(得分:3)

TypeLiteral类是一种解决方法,因为您不能拥有泛型类的类文字。 API doc of Binder(这是来自Google Guice,但同名的Java EE类具有完全相同的目的)给出了如何使用它的示例:

 bind(new TypeLiteral<PaymentService<CreditCard>>() {})
     .to(CreditCardPaymentService.class);

这指定任何类型为PaymentService<CreditCard>的自动注入引用都将由具体类CreditCardPaymentService实现,而PaymentService<Coupon>的选项将由不同<实现< / em> class。没有TypeLiteral,这是不可能的,因为Java编译器将接受PaymentService<CreditCard>.class,只接受PaymentService.class

请注意,这还需要使用匿名子类({}之后的new TypeLiteral<PaymentService<CreditCard>>())才能解决类型擦除问题。

答案 3 :(得分:3)

这是一种让人们在java中绕过泛型擦除的方式。当你想要将一些实现绑定到参数化(通用)接口时,你需要它。在Guice文档中找到了一些用法:

 bind(new TypeLiteral<PaymentService<CreditCard>>() {})
     .to(CreditCardPaymentService.class);

这个确实奇怪的构造是绑定参数化类型的方法。它告诉Guice如何遵守PaymentService类型的元素的注入请求。 CreditCardPaymentService类必须实现PaymentService接口。 Guice目前无法绑定或注入泛型类型,例如Set;必须完全指定所有类型参数。

答案 4 :(得分:0)

我将简化 GUICE 中 TypeLiteral<> 存在的答案/原因:

如果java允许你写:

bind(FooInterface<String>.class).to(FooImplementation.class);

那么你就大功告成了,不需要TypeLiteral<>

但是 java 有泛型的“类型擦除”功能,所以 FooInterface<String>.class 甚至不会被遵守。

所以你使用:

bind(new TypeLiteral<FooInterface<String>>() {}).to(FooImplementation.class);

"new TypeLiteral() {}" 将创建一些匿名类并从中新建一个对象。您可以想象该对象知道有关接口的 tpye 信息的所有信息,因此 GUICE 使用该对象来执行 DI 魔术。