Java 如何获取对象构造函数的参数名称(反射)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2729580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get the parameter names of an object's constructors (reflection)?
提问by Tom
Say I somehow got an object reference from an other class:
假设我以某种方式从另一个类获得了一个对象引用:
Object myObj = anObject;
Now I can get the class of this object:
现在我可以得到这个对象的类:
Class objClass = myObj.getClass();
Now, I can get all constructors of this class:
现在,我可以得到这个类的所有构造函数:
Constructor[] constructors = objClass.getConstructors();
Now, I can loop every constructor:
现在,我可以循环每个构造函数:
if (constructors.length > 0)
{
for (int i = 0; i < constructors.length; i++)
{
System.out.println(constructors[i]);
}
}
This is already giving me a good summary of the constructor, for example a constructor public Test(String paramName) is shown as public Test(java.lang.String)
这已经给了我一个很好的构造函数摘要,例如构造函数 public Test(String paramName) 显示为 public Test(java.lang.String)
Instead of giving me the class type however, I want to get the name of the parameter.. in this case "paramName". How would I do that? I tried the following without success:
然而,我不想给我类类型,而是想获取参数的名称..在这种情况下是“paramName”。我该怎么做?我尝试了以下但没有成功:
if (constructors.length > 0)
{
for (int iCon = 0; iCon < constructors.length; iCon++)
{
Class[] params = constructors[iCon].getParameterTypes();
if (params.length > 0)
{
for (int iPar = 0; iPar < params.length; iPar++)
{
Field fields[] = params[iPar].getDeclaredFields();
for (int iFields = 0; iFields < fields.length; iFields++)
{
String fieldName = fields[i].getName();
System.out.println(fieldName);
}
}
}
}
}
Unfortunately, this is not giving me the expected result. Could anyone tell me how I should do this or what I am doing wrong? Thanks!
不幸的是,这并没有给我预期的结果。谁能告诉我我应该怎么做或者我做错了什么?谢谢!
采纳答案by Roman
This information is lost after compilation and can't be retrieved at runtime.
此信息在编译后丢失,无法在运行时检索。
回答by Adam Paynter
As mentioned in the comments on Roman's answer, the parameter names canbe retrieved if the compiler included debugging symbols, though not through the standard Java Reflection API. Below is an example illustrating how you could obtain parameter names via the debugging symbols using the ASM bytecode library:
正如在Roman's answer的评论中提到的,如果编译器包含调试符号,则可以检索参数名称,但不能通过标准 Java 反射 API 检索。下面是一个示例,说明如何使用ASM 字节码库通过调试符号获取参数名称:
/**
* Returns a list containing one parameter name for each argument accepted
* by the given constructor. If the class was compiled with debugging
* symbols, the parameter names will match those provided in the Java source
* code. Otherwise, a generic "arg" parameter name is generated ("arg0" for
* the first argument, "arg1" for the second...).
*
* This method relies on the constructor's class loader to locate the
* bytecode resource that defined its class.
*
* @param constructor
* @return
* @throws IOException
*/
public static List<String> getParameterNames(Constructor<?> constructor) throws IOException {
Class<?> declaringClass = constructor.getDeclaringClass();
ClassLoader declaringClassLoader = declaringClass.getClassLoader();
Type declaringType = Type.getType(declaringClass);
String constructorDescriptor = Type.getConstructorDescriptor(constructor);
String url = declaringType.getInternalName() + ".class";
InputStream classFileInputStream = declaringClassLoader.getResourceAsStream(url);
if (classFileInputStream == null) {
throw new IllegalArgumentException("The constructor's class loader cannot find the bytecode that defined the constructor's class (URL: " + url + ")");
}
ClassNode classNode;
try {
classNode = new ClassNode();
ClassReader classReader = new ClassReader(classFileInputStream);
classReader.accept(classNode, 0);
} finally {
classFileInputStream.close();
}
@SuppressWarnings("unchecked")
List<MethodNode> methods = classNode.methods;
for (MethodNode method : methods) {
if (method.name.equals("<init>") && method.desc.equals(constructorDescriptor)) {
Type[] argumentTypes = Type.getArgumentTypes(method.desc);
List<String> parameterNames = new ArrayList<String>(argumentTypes.length);
@SuppressWarnings("unchecked")
List<LocalVariableNode> localVariables = method.localVariables;
for (int i = 0; i < argumentTypes.length; i++) {
// The first local variable actually represents the "this" object
parameterNames.add(localVariables.get(i + 1).name);
}
return parameterNames;
}
}
return null;
}
This example uses the ASM library's tree API. If speed and memory are precious, you can refactor the example to use its visitor APIinstead.
回答by Duncan McGregor
Try https://github.com/paul-hammant/paranamer
试试https://github.com/paul-hammant/paranamer
Oh for goodness sake SO, really, you're going to make me enter at least 30 characters to edit an existing answer to make it correct.
哦,看在上帝的份上,真的,你会让我输入至少 30 个字符来编辑现有答案以使其正确。