Unchecked Cast Warning: интерфейс как возвращаемое значение, хранится в классе, реализующем указанный интерфейс - PullRequest
0 голосов
/ 23 января 2020

Моя ситуация, у меня есть функция

public static MyInterface doSomething() {...}

и класс

MyList<O extends MyObject> extends MyListObject<O> implements MyInterface

и:

  • MyObjectA расширяется MyObject
  • MyListObject просто реализует интерфейсы Collection<O> и List<O>

Моя проблема в том, что следующий код

MyList<MyObjectA> var = (MyList<MyObjectA>)doSomething();

выдает предупреждение

Type safety: Unchecked cast from MyInterface to MyList<MyObjectA>

. Почему это так? Я имею в виду, что doOperation() возвращает тип MyInterface, а MyList реализует указанный интерфейс ...

Я надеюсь, что мой пример кода объясняет полную связь между всеми классами и интерфейсами и что я ничего не пропустил.

Ответы [ 3 ]

0 голосов
/ 23 января 2020
interface Flying {
   void fly();
}

class Bird extends Animal implements Flying {
    ...
}

List<Flying> listFlying();

List<Flying> list = listFlying();

Если вы действительно используете только методы интерфейса, вы можете использовать:

list.forEach(flying -> flying.fly());

В противном случае безопасность требует некоторого выравнивания:

List<Bird> birds = list.stream() // Or listFlying().stream()
    .filter(Bird.class::isInstance)
    .map(Bird.class::cast)
    .collect(Collectors.toList());
0 голосов
/ 23 января 2020

По существу, тип в приведении может не содержать <…>, если это не <?>. (Есть исключения из этого правила, но они угловые случаи, и здесь они не имеют отношения.)

Обобщения являются механизмом проверки типов во время компиляции. Во время выполнения класс MyList<MyObjectA> не существует из-за стирания типа. Существует только один MyList класс.

Это означает, что компилятор может генерировать только этот код:

(MyList<?>) doSomething();

Попытка заставить компилятор предположить, что результат имеет спецификацию c generi c тип небезопасен, , потому что код, который будет выполнять приведение, не может проверить это. Таким образом, ваш актерский состав является неконтролируемым.

безопасный способ сделать это - выполнить нестандартные c касты:

MyList<MyObjectA> var = new MyList<>();
MyList<?> list = (MyList<?>) doSomething();
for (Object element : list) {
    var.add((MyObjectA) element);
}

Внимание: var теперь является зарезервированным ключевым словом в Java. Вы должны избегать использования его в качестве имени переменной.

0 голосов
/ 23 января 2020

Вы притворяетесь, что MyInterface был MyList<>, но я почти уверен, что это не так - несмотря на то, что вы не показываете фактическое определение MyInterface.

Говоря метафорически, вы пытаетесь лечить каждого инструмент (MyInterface) как молоток (MyList<>).

Если вы уверены, что doSomething() всегда возвращает MyList, вы можете пометить метод, содержащий приведение, @SuppressWarnings("unchecked") аннотаций. Но тогда зачем вам объявлять doSomething() возвращающим более общий MyInterface в первую очередь?

...