在Java中转换为泛型方法类型变量时的编译器警告

时间:2010-11-07 11:31:51

标签: java generics reflection casting

编辑:我最初接受了我的答案,但我对此并不满意,因为我想要正确使用泛型。所以,我一直在做研究并找到了解决方案。请阅读以下my answer中的相关内容。


这是一段自包含的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 wedge:进程的退出代码是1.
  ---- jGRASP:操作完成。

每次尝试使用相同的代码行编译时,capture#旁边的数字都不同。

那么,究竟是什么问题?当我将调用返回的对象转换为类型变量时,为什么会收到警告?这是否表明我做错了什么?我怎么写这个警告消失了?我宁愿不用注释来压制它,因为这对我来说似乎不是一个解决方案。

3 个答案:

答案 0 :(得分:5)

我对此进行了更多调查,发现我可以通过使用类文字作为运行时类型标记来解决问题,如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 :(得分:1)

为什么要将其投放到T?你为什么不这样做?

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

哦,如果方法可以返回null而expectedReturn不是,那就更好了:

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

答案 2 :(得分:0)

  

那么,究竟是什么问题?为什么   我施放时会收到警告吗?   通过调用返回的对象   类型变量?

方法可以返回任何Object。并且在所有情况下都不能转换为T.

  

这表明我在做什么   有什么不对吗?

将反射和泛型混合起来是不好的做法,imho。

  

我怎么写这个以便   警告消失了吗?

就个人而言,我认为如果不进行重构,你无法避免这种警告。