为什么java在调用方法时不支持访问原语返回值而不通过反射装箱?

9nvpjoqh  于 2021-06-27  发布在  Java
关注(0)|答案(2)|浏览(301)

我注意到java反射支持对基本类型(如boolean或int)的字段进行访问,而无需装箱:

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 { ... }
    //...
}

但是,对于总是返回object的方法只有invoke(…)。当与具有基元返回值的方法一起使用时,这将强制装箱。我想知道为什么还没有人支持这一点。是不是有人要求这样做,还是有严重的问题阻碍了这样做?

twh00eeo

twh00eeo1#

有一种方法,但你需要“更新”的反映。例如:

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);
}

这将编译为:

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

注意签名: ...II)L ,不是 java/lang/Integer 也不是 java/lang/Long . 这些也被称为编译器重载。

zfciruhq

zfciruhq2#

有没有严重的问题阻止它?
是的,返回值不是 invoke() 如果装箱原语,方法参数也会装箱。
e、 如果你有办法的话 boolean foo(String a, int b, double c) ,然后按如下方式调用:

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

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

在自动装箱和varargs之前,应该是这样的,这是编译器实际生成的:

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

为了消除对原语装箱的需要,api需要提供一个重载的 invoke() 方法,而不仅仅是与返回类型匹配的方法。
将会有数以百万计的超载,这将是一个严重的问题。
对各种返回类型进行重载而不同时对参数进行重载是没有意义的,因为您试图用它来修复什么?没有什么。
进行自反方法调用的开销足够大,因此返回值的装箱是不成问题的。

相关问题