Я думаю, что заголовок должен объяснить все это, но на всякий случай...
Я хочу знать, какие риски и потенциальные проблемы, касающиеся кастинга, могут явиться результатом следующего отрывка кода Java:
List<? extends MyObject> wildcardList = someAPI.getList();
List<MyObject> typedList = (List<MyObject>) wildcardList;
Мои мысли - то, что все объекты в wildcardList должны быть экземпляром MyObject (точный тип или подкласс) и поэтому каждый раз, когда объекты получены от typedList затем никогда не должно быть ClassCastException. Это корректно? Раз так, почему компилятор генерирует предупреждение?
Не должно быть никаких проблем, пока вы просто извлекаете объекты из списка. Но это может привести к исключению во время выполнения, если вы вызовете некоторые другие методы, как показано в следующем коде:
List<Integer> intList = new ArrayList<Integer>();
intList.add(2);
List<? extends Number> numList = intList;
List<Number> strictNumList = (List<Number>) numList;
strictNumList.add(3.5f);
int num = intList.get(1); //java.lang.ClassCastException: java.lang.Float cannot be cast to java.lang.Integer
Вы правы насчет извлечения объектов из typedList, это должно работать.
Проблема возникает, когда вы позже добавляете больше объектов в typedList. Если, например, MyObject имеет два подкласса A и B, а wildcardList был типа A, то вы не можете добавить к нему B. Но поскольку typedList имеет родительский тип MyObject, эта ошибка будет поймана только во время выполнения.
Предположим, вы делаете что-то вроде:
List<ChildClassOne> childClassList = new ArrayList<ChildClassOne>();
childClassList.add(childClassOneInstanceOne);
childClassList.add(childClassOneInstanceTwo);
List<? extends MyObject> wildcardList = childClasslist; // works fine - imagine that you get this from a method that only returns List<ChildClassOne>
List<MyObject> typedList = (List<MyObject>) wildcardList; // warning
typedList.add(childClassTwoInstanceOne); // oops my childClassList now contains a childClassTwo instance
ChildClassOne a = childClassList.get(2); // ClassCastException - can't cast ChildClassTwo to ChildClassOne
Это единственная серьезная проблема. Но если вы читаете только из своего списка, все должно быть в порядке.
Это похоже на
List<Object> obj = (List<Object>) new ArrayList<String>();
Надеюсь, проблема очевидна. Список подтипов не может быть приведен к списку супертипов.
В дополнение к уже опубликованным ответам, обратите внимание на следующие
Компилятор выдает предупреждение, если к элементу из этого типа будет осуществлен доступ позже в вашем коде, а это не общий тип, определенный ранее. Также недоступна информация о типе во время выполнения.