I'm struggling with a simple, fundamental Java language question that isn't making sense. I'm passing an Object[]
to a method which expects varargs Object...
, but the method seems to be interpreting the request as new Object[]{Object[]}
. That is, instead of considering the Object[]
as equivalent to Object...
, it seems to be passing the Object[]
as the first element of the varargs, thus wrapping the Object[]
in another array of objects.
I have the following in Java 17:
FooImpl foo = goGetFooImpl();List<?> methodArgs = List.of(); //no method argsObject[] invokeArgs = Stream.concat(Stream.of(foo, methodArgs.stream()).toArray();// this gives me the equivalent of `new Object[]{foo}`// logging `List.of(invokeArgs)` shows `[com.example.FooImpl@…]`MethodHandle barMethodHandle = goLookUpMethodHandle(foo, "bar");methodHandle.invoke(invokeArgs); //expects varargs `foo, arg1, arg2, …`
I get:
java.lang.ClassCastException: Cannot cast [Ljava.lang.Object; to com.example.FooImpl
The method signature I'm calling is MethodHandle.invoke(Object... args)
. It expects varargs, with the first object referencing the target object on which the method is being invoked. So this works:
FooImpl foo = goGetFooImpl();MethodHandle barMethodHandle = goLookUpMethodHandle(foo, "bar");barMethodHandle.invoke(foo);
In this case I don't know ahead of time that there are no further arguments (i.e. methodArgs
above might not be empty), which is why I combined everything into an Object[]
. But even manually testing like this doesn't work:
FooImpl foo = goGetFooImpl();MethodHandle barMethodHandle = goLookUpMethodHandle(foo, "bar");barMethodHandle.invoke(new Object[]{foo});
The reason this is confusing me is that this is such a basic Java issue (a newbie question, really), and I have understood for years that Java would by default consider passing Object[]
to a method expecting Object...
to be equivalent. I had believed that I would have to cast Object[]
to Object
using (Object)invokeArgs
in order for it to be considered the first object of the Object...
(which I don't want). But this seems to be happening anyway without the cast.
The error message seems to be telling me that Java is considering Object[]
to be the first Object of the Object...
varargs, because the method seems to be trying to convert the invokeArgs
itself (which is a Object[]
) to a reference to FooImpl
, which is what is requested as the first argument in the varargs.
This doesn't make sense to me. Either I've misunderstood for years how varargs works, or something weird is going on with the MethodHandle.invoke(…)
method specifically, or I'm just having a mental blank.
Even if MethodHandle.invoke(…)
has some sort of special behavior, aren't the arguments determined at compile time? How could MethodHandle.invoke(…)
have different behavior based upon whether I use invoke(foo)
or invoke(new Object[]{foo})
? During compilation aren't they equivalent, and in either case the compiler will wind up passing new Object[]{foo}
to the method, even in the case of invoke(foo)
?