Java универсальное приведение, не прямой - PullRequest
3 голосов
/ 26 января 2012

Я нашел что-то странное в приведениях в Java, я никогда раньше этого не видел. Приведение фактически не выполняется там, где вы его запрограммировали в общем методе.

Проверка странной вещи.

На хэш-карте:

HashMap<String,Object> map = ...
map.put("hello", "World");
System.err.println((Integer)map.get("hello")); //  -----> ClassCastException

На карте Wrapper

MapWrap wrap = ...
wrap.put("hello", "World");
System.err.println(wrap.get("hello",Integer.class)); // -----> don't cast, print World (i guess because println receives an Object reference but the cast should be done before that).
System.err.println(wrap.get("hello", Integer.class).toString()); // -----> print World + ClassCastException

Код методов:

private <T> T get(String key, Class<T> c){
    return (T)map.get(key);
}

private Object get(String key){
    return map.get(key);
}

Кто-нибудь знает, есть ли у этого механизма имя или знает что-нибудь об этом?

Спасибо

Ответы [ 3 ]

9 голосов
/ 26 января 2012

Состав:

(T) map.get(key);

вообще ничего не делает из-за стирания типа.Метод MapWrap.get() будет удален до:

private Object get(String key, Class<T> c){
    return map.get(key);
}

, который всегда будет работать.Приведение к Integer будет вставлено только в том случае, если вы присваиваете результат этого метода, и, поскольку в первом примере MapWrap вы передаете его методу, который ожидает параметр Object, этого не происходит.

Во втором случае вы пытаетесь вызвать метод Integer.toString(), поэтому приведение к Integer вставляется и завершается неудачей.

Вы уже передаете объект класса правильным способомсделать "общий актерский состав" так:

private <T> T get(String key, Class<T> c){
    return c.cast(map.get(key));
}
3 голосов
/ 26 января 2012

Параметры типов стираются при компиляции.Таким образом, приведение типа (T) становится (Object) в исполняемом файле, поэтому вы получаете первое поведение.

Параметры типа используются только для выполнения типизации во время компиляции и проверки типов.

Во второй строке, однако, я думаю, что компилятор генерирует вызов метода Integer.toString(), поэтому требуется приведение, отсюда и исключение.

См .: Тип Erasure в Javaучебник.

0 голосов
/ 26 января 2012

Я бы назвал это: «шаблоны в Java - это боль»; -).

Строка:

System.err.println(wrap.get("hello",Integer.class));

Использует метод println (Object obj), поэтомунет проблем с типом, поскольку никто не проверяет тип возвращаемого объекта для wrap.get

Во втором случае:

System.err.println(wrap.get("hello", Integer.class).toString());

Это toString () Integer, которыйВызов, и там вы получили с вашим исключением из класса.

К сожалению, Крис указывает, что Java стирает тип из шаблона, но помните, что в методах все еще есть (возможно)

...