Предупреждение компилятора при приведении к переменной типа универсального метода в Java - PullRequest
4 голосов
/ 07 ноября 2010

Редактировать: Первоначально я принял ответ thejh, но меня это не очень устраивало, поскольку я хотел правильно использовать дженерики.Итак, я продолжил исследования и нашел решение.Читайте об этом в моем ответе ниже.


Вот небольшой фрагмент кода Java, который показывает, что я пытаюсь сделать.Он компилируется, запускается и ведет себя правильно.

 1 import java.lang.reflect.Method;
 2 import java.lang.reflect.InvocationTargetException;
 3 
 4 public class Example
 5 {
 6    public static <T> void foo(Method method, String target, Object argument, T expectedReturn) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
 7    {
 8       T actualReturn = (T) method.invoke(target, argument);
 9       System.out.print(actualReturn.equals(expectedReturn));
10    }
11    
12    public static void main(String[ ] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
13    {
14       foo(String.class.getMethod("charAt", int.class), "test", 1, 'e');
15    }
16 }

Запуск этого печатает true на консоли, что я и ожидал.Что меня беспокоит, так это то, что из-за приведения в строку 8 при компиляции я получаю предупреждение следующим образом (кстати, jGRASP - это моя IDE).

----jGRASP exec: javac -g -Xlint: не проверено Sandbox.java
Sandbox.java:8: предупреждение: [не проверено] не проверено приведение
найдено: java.lang.Object
обязательно: T
1предупреждение

---- jGRASP: операция завершена.

Первоначально я пробовал строку 8 без приведения, но не удалось скомпилировать с ошибкой, сообщающей об обнаружении Objectкогда требуется T (invoke возвращает Object).Позже я переписал это так, слепо надеясь избавиться от предупреждения.

T actualReturn = method.getReturnType( ).cast(method.invoke(target, argument));

Но это дает ошибку компиляции, которую я не могу сделать ни головой, ни хвостом.

---- jGRASP exec: javac -g -Xlint: не проверено Sandbox.java
Sandbox.java:8: несовместимые типы
найдено: захват # 898 из?
требуется: T
1 ошибка

---- клин jGRASP: код завершения процесса равен 1.
---- jGRASP: операция завершена.

И это число рядом с capture# отличается каждый раз, когда я пытаюсь скомпилировать с одной и той же строкой кода.

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

Ответы [ 3 ]

5 голосов
/ 11 ноября 2010

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

У меня была правильная идеяс method.getReturnType( ).cast(...), но это не сработало, потому что тип возвращаемого значения getReturnType( ) равен Class<?>, и мне нужно было Class<T>.

Итак, вот как теперь выглядит метод.

public static <T> void foo(Class<T> returnType, Method method, String target, Object argument, T expectedReturn) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
{
    T actualReturn = returnType.cast(method.invoke(target, argument));
    System.out.print(actualReturn.equals(expectedReturn));
}

А вот пример вызова.

foo(Character.class, String.class.getMethod("charAt", int.class), "test", 1, 'e');

, который компилируется без предупреждений и выводит true на консоль.Обратите внимание, что если вы ожидаете, что базовый метод вернет примитив, параметр returnType должен быть соответствующим классом-оболочкой.

1 голос
/ 07 ноября 2010

Почему вы приводите его к T?Почему бы вам не сделать это таким образом?

Object actualReturn = method.invoke(target, argument);
System.out.print(actualReturn.equals(expectedReturn));

О, и если метод может вернуть ноль, а expectedReturn - нет, лучше:

Object actualReturn = method.invoke(target, argument);
System.out.print(expectedReturn.equals(actualReturn));
0 голосов
/ 07 ноября 2010

Так в чем же проблема? Зачем я получаю предупреждение, когда я снимаю объект, возвращаемый вызовом для переменная типа?

Метод может вернуть любой объект. И это не может быть приведено к T во всех случаях.

Означает ли это, что я делаю что-то не так?

плохая практика смешивать рефлексию и дженерики, имхо.

Как я могу написать это так, чтобы предупреждение уходит?

Лично я думаю, что вы не можете избежать этого предупреждения без рефакторинга.

...