|
Spec-Zone .ru
спецификации, руководства, описания, API
|
Одно из изменений в JDK 5.0 то, что class java.lang.Class универсально. Это - интересный пример использования genericity для чего-то другого чем контейнерный class.
Теперь, когда Class имеет параметр типа T, Вы могли бы хорошо спросить, что делает T стенд для? Это обозначает тип что Class объект представляет.
Например, тип String.class Class<String>, и тип Serializable.class Class<Serializable>. Это может использоваться, чтобы улучшить безопасность типов Вашего отражательного кода.
В частности начиная с newInstance() метод в Class теперь возвраты a T, можно получить более точные типы, создавая объекты отражающим образом.
Например, предположите, что Вы должны записать служебный метод, который выполняет запрос базы данных, данный как строка SQL, и возвращает набор объектов в базе данных то соответствие тот запрос.
Один путь состоит в том, чтобы передать в объекте фабрики явно, пишущий код как:
interface Factory<T> { T make();}
public <T> Collection<T> select(Factory<T> factory, String statement) {
Collection<T> result = new ArrayList<T>();
/* Run sql query using jdbc */
for (/* Iterate over jdbc results. */) {
T item = factory.make();
/* Use reflection and set all of item's
* fields from sql results.
*/
result.add(item);
}
return result;
}
Можно вызвать это любой как
select(new Factory<EmpInfo>(){
public EmpInfo make() {
return new EmpInfo();
}}, "selection string");
или можно объявить class EmpInfoFactory поддерживать Factory интерфейс
class EmpInfoFactory implements Factory<EmpInfo> {
...
public EmpInfo make() {
return new EmpInfo();
}
}
и вызовите это
select(getMyEmpInfoFactory(), "selection string");
Нижняя сторона этого решения - то, что оно требует также:
Естественно использовать литерал class в качестве объекта фабрики, который может тогда использоваться отражением. Сегодня (без обобщений) код мог бы быть записан:
Collection emps = sqlUtility.select(EmpInfo.class, "select * from emps");
...
public static Collection select(Class c, String sqlStatement) {
Collection result = new ArrayList();
/* Run sql query using jdbc. */
for (/* Iterate over jdbc results. */ ) {
Object item = c.newInstance();
/* Use reflection and set all of item's
* fields from sql results.
*/
result.add(item);
}
return result;
}
Однако, это не дало бы нам набор точного типа, которого мы требуем. Теперь, когда Class универсально, мы можем вместо этого записать следующее:
Collection<EmpInfo>
emps = sqlUtility.select(EmpInfo.class, "select * from emps");
...
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/* Run sql query using jdbc. */
for (/* Iterate over jdbc results. */ ) {
T item = c.newInstance();
/* Use reflection and set all of item's
* fields from sql results.
*/
result.add(item);
}
return result;
}
Вышеупомянутый код дает нам точный тип набора безопасным с точки зрения типов способом.
Этот метод использования литералов class как маркеры типа времени выполнения является очень полезным приемом, чтобы знать. Это - идиома, это используется экстенсивно в новых API для того, чтобы управлять аннотациями, например.