Тип шаблона, если шаблон является возвращаемым значением (Java) - PullRequest
1 голос
/ 12 ноября 2009

Мне было интересно, каков тип данных переменной шаблона, если для возврата задан шаблон. Я видел это в коде где-то, но я не знаю, куда он приводит значение, полученное из сеанса.

public class RequestObject {
    public <T> T getFromSessionMap(String sessionKey) {
        return (T)session.getAttribute(sessionKey);
    }
}

Код для этого снаружи:

MyClassType type = request.getFromSessionMap("abc");

Строка встречает ClassCastException при приведении к моему объекту. Но когда я добавляю для наблюдения session.getAttribute ("abc"), он показывает, что типом является MyClassType. Любая помощь будет оценена.

Очевидно, что этот специальный код для использования шаблона делает возвращение getFromSessionMap типом переменной и, следовательно, нет необходимости в приведении. Это работает во всех случаях, но внезапно не удалось в одной части кода.

Ответы [ 4 ]

6 голосов
/ 12 ноября 2009

Видимо этот специальный код для использования шаблон делает возврат getFromSessionMap тип переменной и следовательно, нет необходимости в приведении.

По сути, должно быть типизацией где-то между получением результата session.getAttribute(sessionKey) и присвоением MyClassType. Язык Java (и JVM) не позволит некоторому объекту, который не является экземпляром MyClassType (или его подтипом), быть назначенным переменной MyClassType.

Независимо от того, как вы пишете код, должна произойти трансляция типа . И поскольку атрибут (по-видимому) не является MyClassType (или подтипом), вы получаете ClassCastException.

Итак, настоящий вопрос в том, почему вы не получаете ошибку компиляции? И ответ - @SuppressWarnings("unchecked")! Если вы удалите это предупреждение, вы получите сообщение об ошибке «небезопасное преобразование типов» для этой строки:

return (T) session.getAttribute(sessionKey);

По правде говоря, Java не может выполнять приведение (реального) типа к универсальному типу. И это то, на что должно указывать предупреждение / сообщение об ошибке. Фактически, после того, как код скомпилирован, этот код

public <T> T getFromSessionMap(String sessionKey) {
    return (T)session.getAttribute(sessionKey);
}

на самом деле не отличается по смыслу от этого:

public Object getFromSessionMap(String sessionKey) {
    return session.getAttribute(sessionKey);
}

Технически это называется "стирание типа".

Так где же на самом деле происходит проверка типов / типовых трансляций? Ответ в этой строке:

MyClassType type = request.getFromSessionMap("abc");

Даже если вы не написали здесь приведение типов, код, сгенерированный компилятором Java, выполняет преобразование типов перед присвоением значения type. Он должен. Потому что, насколько ему известно, экземпляр, который он назначает, может быть любой тип объекта.

Другие авторы предложили добавить аргумент класса к getFromSessionMap. Само по себе это абсолютно ничего не делает . Если вы также замените тело метода на:

return clazz.cast(session.getAttribute(sessionKey));

вы заставите метод действительно проверять тип. Но это только заставляет ClassCastException быть брошенным в другом месте. И оператор присваивания все равно будет выполнять приведение скрытого типа !!

0 голосов
/ 12 ноября 2009

Любая помощь будет принята, потому что мой код встречает ClassCastException.

Если вы получаете ClassCastException, это означает, что вы пытаетесь преобразовать что-то во что-то, чего нет, как в следующем коде:

Map session = new HashMap();
session.put("date", "2009-11-12");
Date today = (Date) session.get("date"); // tries to convert String to Date

У ClassCastException должно быть подробное сообщение, например "java.lang.String нельзя привести к java.util.Date".

0 голосов
/ 12 ноября 2009

Вы используете приведение типа в теле метода ( '(T) session.getAttribute (sessionKey)' ).

Это означает, что вы явно говорите компилятору 'Я абсолютно уверен, что возвращенный объект IS-A T и готов обработать ошибку, если это не' .

Здесь ваше предположение о типе атрибута было неверным, и вы получили ошибку. Итак, все правильно и среда выполнения уже предоставляет вам реальный тип объекта атрибута, который не является IS-A MyClassType.

0 голосов
/ 12 ноября 2009

В примере вопроса тип возвращаемого значения T. Стираемый тип будет Object как неявно T extends Object. Фактическое приведение выполняется в байт-коде вызывающего метода (вы можете использовать javap -c, чтобы увидеть это).

Как правило, количество сессий «верхнего уровня» должно быть как можно меньше. Одним из преимуществ этого является то, что больше нет необходимости в таких хакерских методах.

...