Пожалуйста, предоставьте некоторую базовую информацию о том, как TypeLiteral
в Google Guice или Java EE используется, будет очень полезно, если бы это было объясняется с помощью простого кода, заранее спасибо
Использование TypeLiteral в java
Ответ 1
Цель TypeLiteral
в Guice - разрешить привязывать классы и экземпляры к общим типам (с указанными параметрами типа), избегая проблемы, возникающие из-за того, что дженерики не воссоединяются на Java, т.е. из-за того, что стирание скрывает разницу между SomeInterface<String>
и SomeInterface<Integer>
во время выполнения. TypeLiteral
позволяет значение универсального параметра выдержать стирание путем создания специального подкласса родового типа.
Пример использования TypeLiteral
:
bind(new TypeLiteral<SomeInterface<String>>(){})
.to(SomeImplementation.class);
Это связывает параметр типа SomeInterface<String>
с SomeImplementation
.
Для получения некоторой справочной информации смотрите этот пост в блоге на токенах супертекста и затем этот по типу литералов.
Ответ 2
Как и все в Guice - модульность, повторное использование и удаление шаблона - это основные понятия всех утилит.
Конечно, все, что вы делаете в Guice, можно передразнивать на Java - ценой большого количества шаблонов Итак... реальный вопрос:
Как мы можем использовать TypeLiterals для записи более модульных/повторно используемых компонентов?
Сила TypeLiterals в Guice заключается в том, что она позволяет вам ссылаться на реализации службы, не определяя, что это за служба.
Давайте начнем с простого списка в программе, где у нас есть много типов списков, которые обрабатываются по-разному:
List<String> myStringList = new ArrayList<String>();
Теперь, как мне обрабатывать эти строки? Во время выполнения нет возможности "знать", что это список строк. Таким образом, часто я мог бы создать factory, например, чтобы получить для меня объекты обработки:
ProcessorFactory.get(String.class).process(myStringList);
Таким образом, я могу использовать factory (с кучей операторов 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 я могу забыть о написании этого factory - скорее, я могу явно использовать классы BIND для процессоров. Преимущество этого заключается в том, что нет статических зависимостей - класс, который должен использовать USE-реализации процессора, не нуждается в какой-либо статической зависимости от factory -rather, классы непосредственно вводятся. Таким образом, я могу легко определить класс, который использует сложные зависимости, не создавая конструктор классов factory. Таким образом, у меня гораздо меньше шаблона:
@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
Класс TypeLiteral
является обходным путем для того, что вы не можете иметь литералы классов для общих типов. API doc 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>>()
), чтобы обойти стирание типа.
Ответ 4
Это способ, которым ребята обходят дженериками в java. Это вам нужно, когда вы хотите связать некоторую реализацию с параметризованным (общим) интерфейсом. Нашли некоторое использование в документах Guice:
bind(new TypeLiteral<PaymentService<CreditCard>>() {})
.to(CreditCardPaymentService.class);
Эта, по общему признанию, нечетная конструкция - это способ привязки параметризованного типа. Он сообщает Guice, как выполнять запрос на инъекцию для элемента типа PaymentService. Класс CreditCardPaymentService должен реализовать интерфейс PaymentService. В настоящее время Guice не может связывать или вводить общий тип, например Set; все параметры типа должны быть полностью указаны.