Java获取函数参数名称的另一种方法

本文介绍了一种在Java 1.8之前版本中获取方法参数名的方法,避免引入额外依赖库。通过分析axis2源码,提取并封装了一个ParameterNames类,方便获取构造函数或方法的参数名。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于获取java 方法的参数名(这里指java 1.8以前的版本,java 1.8已经提供了相关的原生方法),网上可以找到不少文章,这篇文章讲得比较全面了:《Java获取函数参数名称的几种方法》,无外乎是借用asm,javasist等第三方库。

我的项目中也有此需求,看了这篇文章还是觉得比较麻烦,为了这个小小的需求,要多引入一系列依赖库,有点不划算。

我对axis2比较熟悉,知道axis2中在生成client代码时也需要获取方法的参数名,于是通过分析源码找到了axis2的实现代码。
axis2获取java参数名的实现代码的package为org.apache.axis2.description.java2wsdl.bytecode,在axis2核心jar包axis2-kernel-1.6.2.jar中(源码下载地址:axis2-kernel-1.6.2-sources.jar)
好就好在这个package没有引用package之外的代码,所以可以单独提取出来独立调用。

于是我把这部分代码单独复制出来(完整代码参见gitee仓库:
https://gitee.com/l0km/common-java/tree/master/common-base/src/main/java/org/apache/bytecode),并在此基础上封装了一个类ParameterNames,方便调用:

ParameterNames.java

package net.gdface.utils;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import net.gdface.utils.Assert;

import org.apache.bytecode.ChainedParamReader;

/**
 * 获取构造函数或方法的参数名<br>
 * 当不能获取参数名的情况下,
 * {@link returnFakeNameIfFail}为{@code false}时返回{@code null},否则返回返回arg,arg2...格式的替代名<br>
 * {@link returnFakeNameIfFail}默认为{@code true}
 * @author guyadong
 *
 */
public class ParameterNames {
	private final Map<Class<?>, ChainedParamReader> readers = new HashMap<Class<?>, ChainedParamReader>();
	private final Class<?> clazz;
	/** 当获取无法参数名时是否返回arg,arg2...格式的替代名字 */
	private boolean returnFakeNameIfFail = true;
	public ParameterNames setReturnFakeNameIfFail(boolean returnFakeNameIfFail) {
		this.returnFakeNameIfFail = returnFakeNameIfFail;
		return this;
	}

	/**
	 * @param clazz 要构造函数或方法的参数名的类,为{@code null}时所有getParameterNames方法返回{@code null}
	 */
	public ParameterNames(Class<?> clazz) {
		this.clazz = clazz;
		if(null != clazz){
			try {
				Class<?> c = clazz;
				do {
					readers.put(c, new ChainedParamReader(c));
				} while (null != (c = c.getSuperclass()));
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}

	/**
	 * 获取构造函数或方法的参数名
	 * @param reader
	 * @param member 构造函数或方法对象
	 * @return
	 */
	private final String[] getParameterNames(ChainedParamReader reader, Member member) {
		String [] parameterNames = null;
		int paramCount ;
		if (member instanceof Method){
			parameterNames = reader.getParameterNames((Method) member);
			paramCount = ((Method) member).getParameterTypes().length;
		} else if (member instanceof Constructor){
			parameterNames = reader.getParameterNames((Constructor<?>) member);
			paramCount = ((Constructor<?>) member).getParameterTypes().length;
		} else {
			throw new IllegalArgumentException("member type must be Method or Constructor");
		}
		if(this.returnFakeNameIfFail){
			if (null == parameterNames) {
				parameterNames = new String[paramCount];
				for (int i = 0; i < parameterNames.length; i++)
					parameterNames[i] = String.format("arg%d", i);
			}
		}
		return parameterNames;
	}

	/**
	 * 获取构造函数或方法的参数名
	 * @param member 构造函数或方法对象
	 * @return
	 * @see #getParameterNames(ChainedParamReader, Member)
	 */
	public final String[] getParameterNames(Member member) {
		if(null == clazz){
			return null;
		}
		Assert.notNull(member, "member");
		Class<?> declaringClass = member.getDeclaringClass();
		ChainedParamReader reader;
		if (null == (reader = readers.get(declaringClass))) {
			throw new IllegalArgumentException(String.format("%s is not member of %s", member.toString(),
					declaringClass.getName()));
		}
		return getParameterNames(reader, member);
	}
	
	/**
	 * 获取构造函数或方法的参数名<br>
	 * {@code name}为{@code null}时,获取构造函数的参数名
	 * @param name 方法名
	 * @param parameterTypes 构造函数或方法的参数类型
	 * @return
	 * @throws NoSuchMethodException
	 * @see #getParameterNames(String, Class)
	 */
	public final String[] getParameterNames(String name, Class<?>[] parameterTypes) throws NoSuchMethodException {
		if(null == clazz){
			return null;
		}
		try {
			Member member = null == name ? clazz.getConstructor(parameterTypes) : clazz.getMethod(name, parameterTypes);
			return getParameterNames(member);
		} catch (SecurityException e) {
			throw new IllegalArgumentException(e);
		}
	}
}

完整代码参见gitee仓库:https://gitee.com/l0km/common-java/blob/master/common-base/src/main/java/net/gdface/utils/ParameterNames.java

调用示例:

	private static void outputParameterNames(Method method){
		// 抽象方法不能正确获取参数名,只能用假名替代
		System.out.printf("%s abstract = %b\n parameter names:",
				method.getName(),
				Modifier.isAbstract(method.getModifiers()));
		ParameterNames pt = new ParameterNames(method.getDeclaringClass());
		String[] names = pt.getParameterNames(method);
		for(String name:names){
			System.out.print(name + ",");
		}
		System.out.println();
	}

完整的代码参见gitee仓库:
https://gitee.com/l0km/common-java/blob/master/common-base/src/test/java/net/gdface/common/ClassTest.java

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值