След: Премия
Урок: Обобщения
Литералы класса как Маркеры Типа времени выполнения
Домашняя страница > Премия > Обобщения

Литералы класса как Маркеры Типа времени выполнения

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


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Мелкий шрифт
Следующая страница: Больше Забавы с Подстановочными знаками



Spec-Zone.ru - all specs in one place