Использование TypeLiteral в Java - PullRequest
13 голосов
/ 28 декабря 2011

Пожалуйста, предоставьте некоторую основную информацию о том, как TypeLiteral в Google Guice или Java EE, будет очень полезно, если это будет объяснено с помощью простого кода, заранее спасибо

Ответы [ 4 ]

17 голосов
/ 28 декабря 2011

Цель TypeLiteral в Guice - дать вам возможность привязать классы и экземпляры к универсальным типам (с указанными параметрами типа), избегая проблем, связанных с тем фактом, что универсальные шаблоны не реализованы в Java, то есть от того, что стирание скрывает разницу между SomeInterface<String> и SomeInterface<Integer> во время выполнения. TypeLiteral позволяет значению универсального параметра пережить стирание путем создания ad hoc подкласса универсального типа.

Пример использования TypeLiteral:

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

Это связывает параметр типа SomeInterface<String> с SomeImplementation class.

Для получения дополнительной информации посмотрите это сообщение в блоге на токенах супертипа и , затем этот на литералах типа.

4 голосов
/ 28 декабря 2011

Как и все в Guice, модульность, возможность многократного использования и удаление шаблонов являются основными понятиями всех утилит.

Конечно, все, что вы делаете в Guice, может быть имитировано на Java - ценой большого количества шаблонов. Итак ... реальный вопрос:

Как мы можем использовать TypeLiterals для написания более модульных / многократно используемых компонентов?

Сила TypeLiterals в Guice заключается в том, что он позволяет ссылаться на реализации службы, не определяя, что это за служба.

Давайте начнем с простого списка в программе, где у нас есть много типов списков, которые обрабатываются по-разному:

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 я могу забыть о написании этой фабрики - я могу явно связывать классы BIND с процессорами. Преимущество этого состоит в том, что нет никаких статических зависимостей - класс, который должен использовать реализации процессора, НЕ нуждается в статической зависимости от фабрики, классы вводятся напрямую. Таким образом, я могу легко определить класс, который использует сложные зависимости, без необходимости создания конструктора классов, ориентированного на фабрику ... Таким образом, у меня гораздо меньше шаблонов:

@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/

3 голосов
/ 28 декабря 2011

Это способ, которым парни обходят стирание дженериков в Java. Это необходимо, когда вы хотите связать некоторую реализацию с параметризованным (универсальным) интерфейсом. Найдено использование в документации Guice:

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

Эта заведомо странная конструкция является способом связывания параметризованного типа. Он сообщает Guice, как выполнить запрос на инъекцию для элемента типа PaymentService. Класс CreditCardPaymentService должен реализовывать интерфейс PaymentService. Guice в настоящее время не может связывать или вводить универсальный тип, такой как Set; все параметры типа должны быть полностью указаны.

3 голосов
/ 28 декабря 2011

Класс TypeLiteral - это обходной путь для того факта, что у вас не может быть литералов класса для универсальных типов.Документ API Binder (это от 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>>()), чтобы обойти стирание типа.

...