Почему исключение класса считается небезопасной операцией?

1

Почему компилятор Java запускает предупреждение "unchecked cast" при выдаче Class<? extends Object> Class<? extends Object> до Class<Object>? Как может этот бросок, возможно, потерпеть неудачу?

  • 2
    Это потому, что Class<Object> не является родителем, например, Class<String> .
  • 0
    @BoristheSpider: Как так? String расширяет Object . Я понимаю, что компилятор хотел бы запретить мне приведение List<String> к List<Object> потому что тогда мне будет позволено вставлять не-строки в список, но в приведении Class нет опасности. Вы говорите, что авторы языка хотели избежать особого подхода к безопасным классам, таким как Class поэтому они запрещают это по всем направлениям?
Показать ещё 5 комментариев
Теги:
generics
type-safety

4 ответа

3
Лучший ответ

Такой листинг просто небезопасен вообще, и тот факт, что он безопасен для Class не может быть обнаружен. Представьте себе такой класс:

// Hypothetical!
class MyClass<T> extends Class<T> {
    public T someInstance;
}

Теперь, если вопрос был разрешен, вы можете сделать что-то вроде

MyClass<Integer> myClassWithInteger = new MyClass<Integer>();
myClassWithInteger.someInstance = someInteger;

// This is valid
MyClass<? extends Object> myClassWithWildcard = myClassWithInteger; 

// This is NOT valid, but let assume it was:
MyClass<Object> myClassWithObject = myClassWithWildcard; 

// This would be valid, because 'someInstance' was of type 'Object' here
myClassWithObject.someInstance = "someString";

// This is valid. But through the unchecked cast, we silently
// sneaked in an STRING as this instance. So this would fail:
Integer i = myClassWithInteger.someInstance;

Вы спросили в комментарии:

Вы говорите, что авторы языка хотели избежать специального лечения для таких безопасных классов, как Class, поэтому они запрещают это по всем направлениям?

Да. Решающим моментом является то, что вопрос о том, безопасен ли такой бросок или нет, зависит от семантики класса. Безопасность не может быть обнаружена синтаксически.

0

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

Вместо этого вы можете использовать:

Class<? extends Object> clazz = String.class;
Class<?> clazzObject = clazz; // Does not generate Warning.
  • 0
    <? extends Object> и <?> означают одно и то же, поэтому ваш пример не демонстрирует ничего особенного :)
0

Если вы не хотите обеспечить определенный класс интерфейса, используя дженерики, вы должны просто использовать "?" вместо "? extends Object". Компилятор принимает объект для каждого неограниченного общего параметра во время компиляции.

0

Это не говорит, что это незаконно, он говорит, что это небезопасно и может привести к ошибкам во время выполнения.

Рассмотрим следующий код:

List<Integer> li = new ArrayList<Integer>();
List<? extends Number> lf = li;
List<Number> ln = (List<Number>)lf;
ln.add(new Float(1.1));     
Integer value = li.get(0);

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню