Java反射:从属性中检索值的快速方法

Java反射:从属性中检索值的快速方法,java,reflection,Java,Reflection,我想用最快的方法从属性中检索值 我应该使用: public Object getValue(Object obj, Field field) { field.setAccessible(true); return field.get(obj); } public Object getValue(Object obj, Field field) throws Exception { StringBuilder methodName = new StringBuilder(

我想用最快的方法从属性中检索值

我应该使用:

public Object getValue(Object obj, Field field) {
    field.setAccessible(true);
    return field.get(obj);
}
public Object getValue(Object obj, Field field) throws Exception {
    StringBuilder methodName = new StringBuilder();
    methodName.append("get");
    methodName.append(field.getName().substring(0, 1).toUpperCase());
    methodName.append(field.getName().substring(1, field.getName().length()));
    for (Method method : methods) {
        if (method.getName().equals(methodName.toString())) {
            return method.invoke(obj);
        }
    }
}
public Object getValue(Object obj, Field field) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        StringBuilder methodName = new StringBuilder();
        methodName.append("get");
        methodName.append(field.getName().substring(0, 1).toUpperCase());
        methodName.append(field.getName().substring(1, field.getName().length()));
        for (Method method : methods) {
            if (method.getName().equals(methodName.toString())) {
                MethodHandle mh = lookup.findVirtual(obj.getClass(), methodName.toString(), MethodType.methodType(field.getType()));

                return mh.invoke(obj);
            }
        }
    }
或者我应该使用:

public Object getValue(Object obj, Field field) {
    field.setAccessible(true);
    return field.get(obj);
}
public Object getValue(Object obj, Field field) throws Exception {
    StringBuilder methodName = new StringBuilder();
    methodName.append("get");
    methodName.append(field.getName().substring(0, 1).toUpperCase());
    methodName.append(field.getName().substring(1, field.getName().length()));
    for (Method method : methods) {
        if (method.getName().equals(methodName.toString())) {
            return method.invoke(obj);
        }
    }
}
public Object getValue(Object obj, Field field) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        StringBuilder methodName = new StringBuilder();
        methodName.append("get");
        methodName.append(field.getName().substring(0, 1).toUpperCase());
        methodName.append(field.getName().substring(1, field.getName().length()));
        for (Method method : methods) {
            if (method.getName().equals(methodName.toString())) {
                MethodHandle mh = lookup.findVirtual(obj.getClass(), methodName.toString(), MethodType.methodType(field.getType()));

                return mh.invoke(obj);
            }
        }
    }
或者我应该使用:

public Object getValue(Object obj, Field field) {
    field.setAccessible(true);
    return field.get(obj);
}
public Object getValue(Object obj, Field field) throws Exception {
    StringBuilder methodName = new StringBuilder();
    methodName.append("get");
    methodName.append(field.getName().substring(0, 1).toUpperCase());
    methodName.append(field.getName().substring(1, field.getName().length()));
    for (Method method : methods) {
        if (method.getName().equals(methodName.toString())) {
            return method.invoke(obj);
        }
    }
}
public Object getValue(Object obj, Field field) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        StringBuilder methodName = new StringBuilder();
        methodName.append("get");
        methodName.append(field.getName().substring(0, 1).toUpperCase());
        methodName.append(field.getName().substring(1, field.getName().length()));
        for (Method method : methods) {
            if (method.getName().equals(methodName.toString())) {
                MethodHandle mh = lookup.findVirtual(obj.getClass(), methodName.toString(), MethodType.methodType(field.getType()));

                return mh.invoke(obj);
            }
        }
    }

提前感谢。

这里有不同的级别:

  • 字段访问是字段访问。访问该字段的方法将。。。也请访问该字段。只是有更多的开销
  • 您必须随着时间的推移维护代码
第一点建议“直接”字段访问应该总是更快(特别是考虑到这个方法非常短的事实——JIT在内联短方法方面要好得多)。引出第二点:简单地问问自己这三种方法中哪一种最容易阅读和理解

关键是反射呼叫成本很高。方法句柄概念旨在提高成本(通过避免每次使用反射的方法调用进行检查)。因此,如果您真的对寻找“最佳”代码感兴趣,那么答案可能围绕着一个解决方案,该解决方案将计算一次方法句柄,然后再用于后续调用。仅仅为了进行一次调用而实例化一个方法句柄是毫无意义的。从中得不到任何好处-只有在重复使用方法句柄进行调用时,方法句柄才比普通反射“便宜”


当然,真正的答案是:退一步,学习如何正确地编写java代码,然后在您的上下文、环境、数据和代码中进行一些度量。然后得出你的最终结论。我也同意
spi
给出的评论-如果性能对您至关重要,那么反射(或多或少)是一个不可能的问题

其中有不同的级别:

  • 字段访问是字段访问。访问该字段的方法将。。。也请访问该字段。只是有更多的开销
  • 您必须随着时间的推移维护代码
第一点建议“直接”字段访问应该总是更快(特别是考虑到这个方法非常短的事实——JIT在内联短方法方面要好得多)。引出第二点:简单地问问自己这三种方法中哪一种最容易阅读和理解

关键是反射呼叫成本很高。方法句柄概念旨在提高成本(通过避免每次使用反射的方法调用进行检查)。因此,如果您真的对寻找“最佳”代码感兴趣,那么答案可能围绕着一个解决方案,该解决方案将计算一次方法句柄,然后再用于后续调用。仅仅为了进行一次调用而实例化一个方法句柄是毫无意义的。从中得不到任何好处-只有在重复使用方法句柄进行调用时,方法句柄才比普通反射“便宜”


当然,真正的答案是:退一步,学习如何正确地编写java代码,然后在您的上下文、环境、数据和代码中进行一些度量。然后得出你的最终结论。我也同意
spi
给出的评论-如果性能对您至关重要,那么反射(或多或少)是一个不可能的问题

如果您使用的是Java 8,那么

  • 如果您想使用运行反射,那么您应该使用LambdaMetaFactory,它提供与直接方法调用大致相同的性能

  • 如果您希望使代码可配置,但配置在运行时不会更改。然后应该使用AnnotationProcessor来生成代码。它将配置、性能、维护和易用性完美结合


  • 如果您使用的是Java 8,那么

  • 如果您想使用运行反射,那么您应该使用LambdaMetaFactory,它提供与直接方法调用大致相同的性能

  • 如果您希望使代码可配置,但配置在运行时不会更改。然后应该使用AnnotationProcessor来生成代码。它将配置、性能、维护和易用性完美结合


  • 问题在于,您混合了两个基本不兼容的概念。如果您需要高性能,则不使用反射。您使用定义良好的api。反射通常在1-3个数量级(任何好的java书籍都会这么说:)@spi I的性能都不如你。反射不是检索值的最快方法。但不幸的是,我无法改变这一点。我必须使用反射。但是在所有的可能性中,我想知道什么是最好的。感谢您的回复:)问题是您混合了两个基本不兼容的概念。如果您需要高性能,则不使用反射。您使用定义良好的api。反射通常在1-3个数量级(任何好的java书籍都会这么说:)@spi I的性能都不如你。反射不是检索值的最快方法。但不幸的是,我无法改变这一点。我必须使用反射。但是在所有的可能性中,我想知道什么是最好的。谢谢你的回复:)回答得也很好。特别是链接到另一个答案是非常有帮助的。不过,您可能还想为第二点添加一个链接。@GhostCat-telled的链接是个好主意。我会很感激的。回答也很好。特别是链接到另一个答案是非常有帮助的。不过,您可能还想为第二点添加一个链接。@GhostCat-telled的链接是个好主意。我将不胜感激。