简体   繁体   中英

Why does Java not support accessing primitive return values when invoking methods without boxing via reflection?

I noticed that Java Reflection supports access on fields of primitive types such as boolean or int without boxing:

public final class Field extends AccessibleObject implements Member {
    //...
    public boolean getBoolean(Object obj) throws IllegalArgumentException, IllegalAccessException { ... }
    public char getChar(Object obj) throws IllegalArgumentException, IllegalAccessException { ... }
    public byte getByte(Object obj) throws IllegalArgumentException, IllegalAccessException { ... }
    public short getShort(Object obj) throws IllegalArgumentException, IllegalAccessException { ... }
    public int getInt(Object obj) throws IllegalArgumentException, IllegalAccessException { ... }
    public long getLong(Object obj) throws IllegalArgumentException, IllegalAccessException { ... }
    public float getFloat(Object obj) throws IllegalArgumentException, IllegalAccessException { ... }
    public double getDouble(Object obj) throws IllegalArgumentException, IllegalAccessException { ... }
    //...
}

However, there is only invoke(...) for methods which always returns Object. This forces boxing when it is used with methods with primitive return values. I wonder why there is no support for that yet. Has it not been asked for or are there serious issues which prevent it?

are there serious issues which prevent it?

Yes, the return value is not the only part of invoke() that boxes primitives, the method arguments are boxed too.

Eg if you have method boolean foo(String a, int b, double c) , then you invoke it like this:

String a = ...;
int b = ...;
double c = ...;

boolean result = method.invoke(obj, a, b, c);

Before auto-boxing and varargs, it would have been like this, which is what the compiler actually generates:

boolean result = method.invoke(obj,
                               new Object[] { a,
                                              Integer.valueOf(b)/*auto-boxing*/,
                                              Double.valueOf(c)/*auto-boxing*/ })
                       .booleanValue()/*auto-unboxing*/;

To eliminate the need for boxing of primitives, the API would need to provide an overloaded invoke() method that exactly matches the signature of the method, not just one that matches the return type.

There would have to be a gazillion overloads, and that would be a serious issue.

Making overloads for the various return types without also making overloads for the arguments wouldn't make sense, because what are you trying to fix with that? Nothing.

The overhead of making a reflexive method call is high enough that the boxing of the return value is a non-issue.

There is a way, but you need the "newer" reflection. For example:

static class Test {

    public long go(int x, int y) {
        return x + y;
    }

}


static void methodHandles() throws Throwable {
    MethodType mt = MethodType.methodType(long.class, int.class, int.class);
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle goMethod = lookup.findVirtual(Test.class, "go", mt);

    long result = (long)goMethod.invokeExact(new Test(), 40, 2);
    System.out.println(result);
}

This will compile to:

Method java/lang/invoke/MethodHandle.invokeExact:(LDeleteMe$Test;II)J

Notice the signature: ...II)L , not java/lang/Integer nor java/lang/Long . These are also called compiler overloads.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM