为什么Java不支持在不通过反射装箱的情况下调用方法时访问基元返回值



我注意到Java反射支持在没有装箱的情况下访问布尔或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(…(。当它与具有基元返回值的方法一起使用时,这将强制装箱。我想知道为什么还没有人支持这一点。它是否没有被要求,或者是否存在严重的问题阻碍了它?

是否存在严重的问题阻止了它?

是的,返回值并不是invoke()中装箱基元的唯一部分,方法参数也被装箱。

例如,如果你有方法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()方法,该方法与该方法的签名完全匹配,而不仅仅是与返回类型匹配的方法。

必须有大量的过载,这将是一个严重的问题。

为各种返回类型重载而不为参数重载是没有意义的,因为你想用它来解决什么问题?没有什么

进行反射式方法调用的开销足够高,因此返回值的装箱是不成问题的。

有一种方法,但您需要;更新的";反射例如:

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/Integerjava/lang/Long。这些也称为编译器重载。

最新更新