2016-04-15 7 views

ответ

4

Я считаю, что это причина предупреждения: Java допускает downcasting, то есть литье объекта типа 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() (как и все Object). Но это бросило 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, некоторые из того, что я написал может быть неправильным.)

Смежные вопросы