gpt4 book ai didi

java - 如何获取调用静态方法的类?

转载 作者:行者123 更新时间:2023-12-02 00:58:33 25 4
gpt4 key购买 nike

这是我的代码:

class A {

public static void doIt() {
//Class currentClass = new Object() { }.getClass().getEnclosingClass();
//Class currentClass = MethodHandles.lookup().lookupClass();
String currentClass = Thread.currentThread().getStackTrace()[1].getClassName();
System.out.println("CALLING CLASS:" + currentClass);
}
}

class B extends A { }

public class NewMain {

public static void main(String[] args) {
A.doIt();
B.doIt();
}
}

如您所见,doIt 方法可以由 AB 类调用。在 doIt 中,我想知道使用哪个类来调用方法(AB)。是否可以?我尝试的三种解决方案都不起作用 - 它总是显示 A 类。

最佳答案

起初,我认为这是不可能的,因为 java 编译器可以确定将调用哪个方法并发出相同的指令。

事实证明,它实际上记录了类的调用方式。

所以,现在的问题是:

  • 我们如何获取调用该方法的位置?
  • 我们如何使用这些信息来获取方法的调用方式?

第一个很简单:我们使用 StackWalker,它可以给我们 bytecode index .

现在我们只需要解析该类,查看该字节码索引处的指令,并找出如何调用该方法。

我为此使用了 ASM,但它可能是错误的工具。

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.lang.StackWalker.StackFrame;
import java.util.Set;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;

class CallingClassVisitor extends ClassVisitor {

private final StackFrame where;
String ownerClass = null;

public CallingClassVisitor(StackFrame where) {
// We need a backing ClassWriter, so the Label is resolved.
super(ASM8, new ClassWriter(0));
this.where = where;
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
MethodVisitor parent = super.visitMethod(access, name, descriptor, signature, exceptions);
if (name.equals(where.getMethodName()) && descriptor.equals(where.getDescriptor())) {
return new CallingMethodVisitor(where, parent);
} else {
return parent;
}
}

class CallingMethodVisitor extends MethodVisitor {

private final StackFrame where;
public CallingMethodVisitor(StackFrame where, MethodVisitor parent) {
super(ASM8, parent);
this.where = where;
}

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
Label lbl = new Label();
visitLabel(lbl);
if (lbl.getOffset() == where.getByteCodeIndex()) {
ownerClass = owner;
}
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
}

public String getOwnerClass() {
return ownerClass;
}
}



class A {

static final StackWalker SW = StackWalker.getInstance(Set.of(StackWalker.Option.RETAIN_CLASS_REFERENCE));

public static void doIt() {
StackFrame sf = SW.walk(s -> s.skip(1).findFirst()).orElseThrow();
InputStream source = sf.getDeclaringClass().getClassLoader()
.getResourceAsStream(sf.getClassName().replace('.', '/') + ".class");
try {
CallingClassVisitor ccv = new CallingClassVisitor(sf);
new ClassReader(source).accept(ccv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
String how = ccv.getOwnerClass();
System.out.println(how);
} catch (IOException e) {
throw new UncheckedIOException(e);
}

}
}

class B extends A { }

public class NewMain {

public static void main(String[] args) {
A.doIt();
B.doIt();
}
}

最后,我不确定您的要求是否值得付出这样的努力。

关于java - 如何获取调用静态方法的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61011291/

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