Предупреждение универсального метода Java Непроверенное приведение

Я написал метод замены View.findViewById(int id), но получил предупреждение: введите здесь описание изображения

Есть ли проблема в этом методе? Или как этого избежать?


person L. Swifter    schedule 15.04.2016    source источник


Ответы (1)


Я считаю, что это причина предупреждения: Java допускает понижающее приведение, то есть приведение объекта типа X к подклассу X. Однако это требует проверки во время выполнения. Например:

Object x1 = <... something that returns an object that may be a String ...>;
String x2 = (String)x1;

Актерский состав попытается относиться к x1 как к String. Но x1 может быть любым Object. Это может быть, а может и не быть String. Приведение работает, только если x1 на самом деле является String; в противном случае вы получите ClassCastException во время выполнения.

Проблема в вашем коде заключается в том, что T является подклассом View, а это означает, что приведение типов обычно приводит к выполнению такой же проверки во время выполнения. Однако из-за стирания типа программа фактически не имеет информации о классе T в этом месте кода, что означает, что она не может выполнить проверку. Таким образом, вы получаете предупреждение о том, что программа использует непроверенную операцию. Программа не может гарантировать, что при возвращении этого метода возвращенный объект действительно будет экземпляром класса T.

Я попробовал несколько тестовых примеров и обнаружил, что проверка часто выполняется для инструкции, которая вызывает универсальный метод. Предположим, что View2 расширяет View, и вы хотите использовать find таким образом, чтобы возвращалось View2. Потом:

View2 v = YourClass.<View2>find(x, id);

Если объект, найденный findViewById, на самом деле не View2, вы получите ClassCastException. Но:

View v = YourClass.<View2>find(x, id);

Предположим, что findViewById возвращает какое-то другое представление. Основываясь на моих тестах, это не вызовет исключения, даже если параметр типа равен View2; так как это назначается в View, который будет работать нормально, если результатом является какое-то другое представление, проверка на View2 никогда не происходит.

String s = YourClass.<View2>find(x, id).toString();

Предположим, что findViewById возвращает какое-то другое представление. Когда я пробовал это, я думал, что это не вызовет исключения, потому что другое представление также будет иметь toString() (как и все Objects). Но это бросило ClassCastException.

Я не знаю, есть ли хороший способ это исправить. Одна из возможностей — добавить третий параметр к find для обозначения класса T и использовать его метод cast:

public static <T extends View> T find(View view, int id, Class<T> theClass) {
    return theClass.cast(view.findViewById(id));
}

View v = YourClass.find(x, id, View2.class);

Это работает — выдается исключение из метода cast(), если findViewById возвращает неправильный класс. Однако добавление третьего параметра для каждого использования может оказаться не очень привлекательным, даже если это позволит исключить явный параметр универсального типа из вызова.

Я думаю, что это тот случай, когда можно игнорировать предупреждение и использовать @SuppressWarnings("unchecked"), чтобы предотвратить появление предупреждения, если вы согласны с возможностью того, что иногда программа может продолжить работу вместо того, чтобы генерировать исключение, когда findViewById возвращает неправильный вид зрения.

(Отказ от ответственности: Мои тесты проводились с использованием Java 8. Я не использовал ничего, что было бы недопустимо в Java 7. Но если Android еще не полностью реализовал Java 7, некоторые из моих написал, может ошибся)

person ajb    schedule 15.04.2016