微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么在通过反射调用没有装箱的方法时,Java 不支持访问原始返回值?

如何解决为什么在通过反射调用没有装箱的方法时,Java 不支持访问原始返回值?

我注意到 Java Reflection 支持在没有装箱的情况下访问原始类型的字段,例如 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(...)。当它与具有原始返回值的方法一起使用时,这会强制装箱。 我想知道为什么还没有支持。是否没有被要求或是否存在阻止它的严重问题?

解决方法

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

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

例如如果您有方法 boolean foo(String a,int b,double c),那么您可以像这样调用它:

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

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

在自动装箱和可变参数之前,它会是这样的,这就是编译器实际生成的:

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。