Edit: I initially accepted thejh's answer, but I wasn't really satisfied with it since I wanted to make proper use of generics. So, I kept doing research and found a solution. Read about it in my answer below.
Here's a little self-contained piece of Java code which shows what I'm trying to do. It compiles, runs, and behaves correctly.
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 }
Running this prints true
to the console, which is what I expected. What's bothering me is that, due to the cast on line 8, I'm getting a warning when I compile it, as follows (jGRASP is my IDE, by the way).
----jGRASP exec: javac -g -Xlint:unchecked Sandbox.java
Sandbox.java:8: warning: [unchecked] unchecked cast found : java.lang.Object required: T 1 warning----jGRASP: operation complete.
Originally, I tried line 8 without the cast, but that failed to compile with an error complaining about finding an Object
when it required T
(invoke
returns an Object
). Later on, I rewrote it like this, blindly hoping to get rid of the warning.
T actualReturn = method.getReturnType( ).cast(method.invoke(target, argument));
But that gives a compile error that I can't make head nor tail of.
----jGRASP exec: javac -g -Xlint:unchecked Sandbox.java
Sandbox.java:8: incompatible types found : capture#898 of ? required: T 1 error----jGRASP wedge: exit code for process is 1.
----jGRASP: operation complete.
And that number next to capture#
is different each time I try to compile with that same line of code.
So, what exactly is the problem? Why am I getting the warning when I cast the object returned by invoke to the type variable? Does that indicate that I'm doing something wrong? How can I write this so that the warning goes away? And I'd prefer not to suppress it with an annotation, as that doesn't seem like much of a solution to me.
I looked into this some more and found that I could solve the problem by using class literals as runtime type tokens, as discussed in the Java Tutorials.
I had the right idea with method.getReturnType( ).cast(...)
, but it didn't work because the return type of getReturnType( )
is Class<?>
, and I needed Class<T>
.
So, here's what the method looks like now.
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));
}
And here's a sample call.
foo(Character.class, String.class.getMethod("charAt", int.class), "test", 1, 'e');
That compiles without warnings and prints true
to the console. Note that if you're expecting the underlying method to return a primitive, the returnType parameter needs to be its respective wrapper class.
Why do you cast it to T
? Why don't you do it this way?
Object actualReturn = method.invoke(target, argument);
System.out.print(actualReturn.equals(expectedReturn));
Oh, and in case the method could return null and expectedReturn
isn't, this is better:
Object actualReturn = method.invoke(target, argument);
System.out.print(expectedReturn.equals(actualReturn));
So, what exactly is the problem? Why am I getting the warning when I cast the object returned by invoke to the type variable?
Method can return any Object. And it can't be cast to T in all cases.
Does that indicate that I'm doing something wrong?
it's bad practice to mix reflection and generics, imho.
How can I write this so that the warning goes away?
Personally, I think you can't avoid this warning without refactoring.
精彩评论