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 для того, чтобы управлять аннотациями, например.