有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

jakarta ee在java中使用TypeLiteral

请提供一些关于如何在Google Guice或Java EE中使用^{}的基本信息,如果能够使用简单的代码进行解释,将非常有帮助,提前感谢


共 (5) 个答案

  1. # 1 楼答案

    Guice中^{}的目的是允许您将类和实例绑定到泛型类型(指定类型参数),从而避免泛型在Java中没有具体化这一事实所导致的问题,也就是说,擦除在运行时隐藏了SomeInterface<String>SomeInterface<Integer>之间的差异TypeLiteral通过创建泛型类型的特殊子类,允许泛型参数的值在擦除后仍然有效

    TypeLiteral的用法示例:

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

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

    有关一些背景信息,请查看超级类型标记上的this blog post和类型文字上的then this one

  2. # 2 楼答案

    对于泛型类型不能有类文本这一事实,TypeLiteral类是一种变通方法。API doc of ^{}(这是来自Google Guice,但同名的Java EE类具有完全相同的用途)给出了一个如何使用它的示例:

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

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

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

  3. # 3 楼答案

    与Guice中的任何东西一样,模块化、可重用性和样板文件的删除是所有实用程序的核心概念

    当然,您在Guice中所做的任何事情都可以在Java中模仿——代价是大量的样板文件,所以。。。真正的问题是:

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

    Guice中TypeLiterals的强大之处在于,它允许您引用服务的实现,而无需定义该服务是什么

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

    List<String> myStringList = new ArrayList<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/

  4. # 4 楼答案

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

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

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

  5. # 5 楼答案

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

    如果java允许您编写:

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

    这样就完成了,不需要使用TypeLiteral<>

    但是java对泛型有这种“类型擦除”的功能,所以FooInterface<String>.class甚至不会被编译

    所以你使用:

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

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