jvm java运行时如何获取方法的参数名和参数值

发布于 2021-11-30 15:01:31 字数 209 浏览 535 评论 2

我现在想写一个log输出,输出格式大体有这几个:类名,方法名,{{参数名:参数值}, ...}

在java的本身中只提供了 “类名,方法名”这两个获取方法,方法的参数名jdk<1.8时,读字节码;jdk>=1.8时,反射;但是参数值只能是运行时拿到,所以我下了openjdk源码,希望有人能给我指点一下,获取{参数名:参数值}去c++的哪里可以拿到,给我指条路,多谢!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

画骨成沙 2021-11-30 20:20:21

思路错了吧。。。

另外,JDK 1.8 以下,读字节码默认也是获取不到参数名的。

Java的字节码文件默认不存储参数名称。在使用javac编译时,如果开启-g:{vars}选项,可以增加Local variable debugging information。对java方法,参数实际是按照局部变量来存储的,所以可以获取参数名称;但对于java接口中的方法声明,这种方法就无法获取参数名称。

柠檬 2021-11-30 17:00:01

这应该分成两个问题,1.如何获取参数值. 2.如何获取参数名,

1.如何获取参数值。这个是运行时的数据,你程序处理下获取就好了。比如写一个代理

2.参数名是在编译的时候就写入到class文件的。,而这些方法的参数在class中就是一个局部变量。class对于局部变量的定义和存储专门有张表。

单纯通过反射目前好像没有办法,通过字节码解析倒是可以

比如下面代码

public static void staticMethod(String args1, String args2) {

}

局部变量表:

        [pc: 0, pc: 1] local: args1 index: 0 type: java.lang.String

        [pc: 0, pc: 1] local: args2 index: 1 type: java.lang.String

pc 0是每个字节码指令的程序计数器。[pc: 0, pc: 1] local: args1 index: 0 type: java.lang.String就是说在程序第0个指令到第1个指令的局部变量数组下标为0的变量类型是String变量名是args1.

public static void nonStaticMethod(String args1, String args2) {

}

局部变量表;

        [pc: 0, pc: 1] local: this index: 0 type: asmtest.Test

        [pc: 0, pc: 1] local: args1 index: 1 type: java.lang.String

        [pc: 0, pc: 1] local: args2 index: 2 type: java.lang.String

这个方法比上面的方法多了一个this。因为这个方法是非静态方法。

所以如果要获取参数名需要解析字节码。这里给你一段代码使用ASM

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

public class ReadMethodArgNameClassVisitor extends ClassVisitor {

	public Map<String, List<String>> nameArgMap = new HashMap<String, List<String>>();
	
	public ReadMethodArgNameClassVisitor() {
		super(Opcodes.ASM5);
	}
	
	@Override
	public MethodVisitor visitMethod(int access, String name, String desc,
			String signature, String[] exceptions) {
		Type methodType = Type.getMethodType(desc);
		int len = methodType.getArgumentTypes().length;
        List<String> argumentNames = new ArrayList<String>();
		nameArgMap.put(name, argumentNames);
		ReadMethodArgNameMethodVisitor visitor = new ReadMethodArgNameMethodVisitor(Opcodes.ASM5);
		visitor.argumentNames = argumentNames;
		visitor.argLen = len;
		return visitor;
	}
}

import java.util.List;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

public class ReadMethodArgNameMethodVisitor extends MethodVisitor {

	public List<String> argumentNames;
	
	public int argLen;
	
	public ReadMethodArgNameMethodVisitor(int api) {
		super(api);
	}

	@Override
	public void visitLocalVariable(String name, String desc, String signature,
			Label start, Label end, int index) {
		if("this".equals(name)) {
			return;
		}
		if(argLen-- > 0) {
			argumentNames.add(name);
		}
	}

}

public class POJO {

	public void say(String message, int times){
	}
	
}


import java.io.IOException;
import java.util.List;
import java.util.Map.Entry;

import org.objectweb.asm.ClassReader;

public class Test {

	public static void main(String... args1) throws IOException {
        ClassReader cr = new ClassReader("POJO");
		ReadMethodArgNameClassVisitor classVisitor = new ReadMethodArgNameClassVisitor();
		cr.accept(classVisitor, 0);
		for(Entry<String, List<String>> entry : classVisitor.nameArgMap.entrySet()) {
		    System.out.println(entry.getKey());
			for(String s : entry.getValue()) {
			    System.out.println("    " + s);
			}
		}
	}

}

使用asm版本是

<dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm-all</artifactId>
    <version>5.0.3</version>
</dependency>

这里存在一个隐患,如果有些class文件做了加密混淆吧局部变量表里面的变量名改变了,那就没法获得源码级别的参数名了。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文