gpt4 book ai didi

java - 是否有一种快速的反射字段访问方法?

转载 作者:行者123 更新时间:2023-12-01 13:56:00 25 4
gpt4 key购买 nike

我需要一种方法来访问具有反射性质的字段,而不会影响标准反射的性能。我已经弄清楚如何使用特权查找句柄通过 LambdaMetaFactory 使用方法/构造函数来做到这一点,但是,我似乎无法弄清楚如何获得字段访问权限。
我以为我可以通过 javaassist 之类的东西生成一个内部类,理论上它应该可以访问该字段,但没有成功,抛出一个 IllegalAccessError。
如果我可以重新定义类,那么任务将是微不足道的,因为我可以生成 getter/setter 方法。但是,对于我正在处理的项目,我无法使用代理,因为它需要在运行时加载,并且我必须从工具中动态导入附加 api。
有人可以在这里指导我正确的方向吗?我研究了 LambdaMetaFactory 如何为方法生成它的接口(interface),并试图用没有成功的字段来镜像它。字段和方法的内部是否存在一些不同之处,使得如果不重新定义就无法完成这项任务?

最佳答案

对于 OpendJDK(以及在其上构建的 JDK),LambdaMetaFactory生成一个非常普通的类文件(仅访问 private 另一个类的成员)并使用 sun.misc.Unsafe 中的特殊方法, 创建一个 anonymous class .
创建一个访问字段的类似类文件很简单,并用它创建一个匿名类确实有效,可以使用以下快速&脏程序演示:

public class Generator {
public static void main(String[] args) throws Throwable {
ToIntFunction<Thread> ft=generateIntFieldAccessor(Thread.class, "threadStatus");
System.out.println(ft.applyAsInt(Thread.currentThread()));
}

private static <X> ToIntFunction<X> generateIntFieldAccessor(
Class<? super X> c, String name) throws Throwable {

byte[] code = Generator.generateIntReaderCode(c.getDeclaredField(name));
Class<?> unsafe = Class.forName("sun.misc.Unsafe");
Field u = unsafe.getDeclaredField("theUnsafe");
u.setAccessible(true);
Object theUnsafe = u.get(null);
Class<ToIntFunction<X>> gen = (Class<ToIntFunction<X>>)
MethodHandles.publicLookup().bind(theUnsafe, "defineAnonymousClass",
MethodType.methodType(
Class.class, Class.class, byte[].class, Object[].class))
.invokeExact(c, code, (Object[])null);
return gen.getConstructor().newInstance();
}

private static final String HEAD = "Êþº¾\0\0\0004\0\24\7\0\21\7\0\t\7\0\n\7\0\22"
+ "\n\0\2\0\6\f\0\13\0\f\t\0\4\0\b\f\0\23\0\20\1\0\20java/lang/Object\1\0\40"
+ "java/util/function/ToIntFunction\1\0\6<init>\1\0\3()V\1\0\4Code\1\0\n"
+ "applyAsInt\1\0\25(Ljava/lang/Object;)I\1\0\1I";
private static final String TAIL = "\0001\0\1\0\2\0\1\0\3\0\0\0\2\0\1\0\13\0\f\0"
+ "\1\0\r\0\0\0\21\0\1\0\1\0\0\0\5*·\0\5±\0\0\0\0\0\21\0\16\0\17\0\1\0\r\0\0"
+ "\0\24\0\1\0\2\0\0\0\b+À\0\4´\0\7¬\0\0\0\0\0\0";

public static byte[] generateIntReaderCode(Field f) {
return new ByteArrayOutputStream(HEAD.length() + TAIL.length() + 100) {
@SuppressWarnings("deprecation") byte[] get() {
HEAD.getBytes(0, count = HEAD.length(), buf, 0);
try(DataOutputStream dos = new DataOutputStream(this)) {
String decl = f.getDeclaringClass().getName().replace('.', '/');
dos.writeByte(1); dos.writeUTF(decl+"$"+f.getName()+"$access");
dos.writeByte(1); dos.writeUTF(decl);
dos.writeByte(1); dos.writeUTF(f.getName());
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
int dynSize = count;
byte[] result = Arrays.copyOf(buf, dynSize + TAIL.length());
TAIL.getBytes(0, TAIL.length(), result, dynSize);
return result;
}
}.get();
}
}
Demo on Ideone
当然,对于生产代码,您最好使用常用的代码生成库之一,以获得可维护的工厂代码。例如,OpenJDK 的 LambdaMetaFactory在后台使用 ASM 库。
如果您尝试实现类似解决方案失败,您必须发布您尝试过的内容,以便我们帮助确定问题。但也许,知道一般情况下这是可能的,已经对你有所帮助。

关于java - 是否有一种快速的反射字段访问方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63419740/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com