是否可以使用反射获取方法的方法的名称 Java?

如果我有这样的课程:


public class Whatever
{
public void aMethod/int aParam/;
}


有没有办法找出这一点
aMethod

使用命名的参数
aParam

, 那是类型
int

?
已邀请:

董宝中

赞同来自:

在 Java 8 您可以执行以下操作:


import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

public final class Methods {

public static List<string> getParameterNames/Method method/ {
Parameter[] parameters = method.getParameters//;
List<string> parameterNames = new ArrayList&lt;&gt;//;

for /Parameter parameter : parameters/ {
if/!parameter.isNamePresent/// {
throw new IllegalArgumentException/"Parameter names are not present!"/;
}

String parameterName = parameter.getName//;
parameterNames.add/parameterName/;
}

return parameterNames;
}

private Methods//{}
}


所以对于你的课程
Whatever

我们可以进行手动测试:


import java.lang.reflect.Method;

public class ManualTest {
public static void main/String[] args/ {
Method[] declaredMethods = Whatever.class.getDeclaredMethods//;

for /Method declaredMethod : declaredMethods/ {
if /declaredMethod.getName//.equals/"aMethod"// {
System.out.println/Methods.getParameterNames/declaredMethod//;
break;
}
}
}
}


这应该需要
[aParam]

, 如果你通过了
-parameters

对你的编译器的争论 Java 8.

为了 Maven 用户:


<properties>
<!-- PLUGIN VERSIONS -->
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
<!-- OTHER PROPERTIES -->
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-compiler-plugin</artifactid>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<!-- Original answer -->
<compilerargument>-parameters</compilerargument>
<!-- Or, if you use the plugin version >= 3.6.2 -->
<parameters>true</parameters>
<testcompilerargument>-parameters</testcompilerargument>
<source/>${java.version}
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>


有关更多信息,请参阅以下链接:

http://docs.oracle.com/javase/ ... .html
http://openjdk.java.net/jeps/118
https://docs.oracle.com/javase ... .html
</string></string>

詹大官人

赞同来自:

总结

获取参数名称

如果在编译期间启用调试信息,则可以进行。 看
https://coderoad.ru/6759880/
更多细节

否则,接收参数名称是不可能的

获取参数类型可以使用
method.getParameterTypes//


为了为编辑器编写自动填充功能 /正如你在其中一个评论中所说的那样/ 有几种选择:

使用
arg0

,
arg1

,
arg2

等等。

使用
intParam

,
stringParam

,
objectTypeParam

等等。

使用上面的组合 - 首先是非暴力类型,以及第二种原始类型。

根本不显示参数的名称 - 只有类型。

帅驴

赞同来自:

图书馆 Paranamer 它创建了解决同样的问题。

它正试图以几种不同的方式识别这些方法的名称。 如果类是用调试编译的,它可以通过读取类的字节代码来提取信息。

另一种方法是在汇编之后在类的字节代码中输入闭合静态成员,但在其放置之前 jar. 然后,他反映了在执行期间从类中提取此信息。

https://github.com/paul-hammant/paranamer
我使用这个图书馆有问题,但最终我设法努力工作。 我希望报告伴随的问题。

裸奔

赞同来自:

看 org.springframework.core.DefaultParameterNameDiscoverer 班级


DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer//;
String[] params = discoverer.getParameterNames/MathUtils.class.getMethod/"isPrime", Integer.class//;

詹大官人

赞同来自:

是的。

代码

必须由汇编 Java 8 兼容编译器

使用存储正式参数名称的选项 /选项

-parameters

/.

然后这个代码片段应该有效:


Class<string> clz = String.class;
for /Method m : clz.getDeclaredMethods/// {
System.err.println/m.getName///;
for /Parameter p : m.getParameters/// {
System.err.println/" " + p.getName///;
}
}


</string>

董宝中

赞同来自:

您可以获得反射方法并确定其类型的参数。 查看
http://java.sun.com/j2se/1.4.2 ... %2529
但是,您无法判断使用的参数的名称。

石油百科

赞同来自:

我是可能的。 Spring MVC 3 是吗,但我没时间看看究竟。

方法参数名称的巧合
到 URI 可变模板的名称可以
如果您的代码编译,则只能完成这一点
包括调试。 如果你有
如果不包括调试,则必须
指定模板的名称 URI
字段中的变量名称 @PathVariable
注释为了领带
允许的变量值 name to
方法参数。 例如:

取自
http://static.springsource.org ... pping

小姐请别说爱

赞同来自:

虽然这是不可能的 /随着其他例子表明/, 你

你可以

使用注释传输参数的名称并通过反射获取。

不是最纯粹的决定,但它就是这样。 某些Web服务确实可以保存参数的名称。 /即:部署 WSs 从 glassfish/.

帅驴

赞同来自:


http://docs.oracle.com/javase/ ... .html
, 这是一个为此设计的摘要。

喜特乐

赞同来自:

所以你应该能做:


Whatever.declaredMethods
.find { it.name == 'aMethod' }
.parameters
.collect { "$it.type : $it.name" }


但是你可能会得到这样的清单:


["int : arg0"]


https://issues.apache.org/jira/browse/GROOVY-7423
因此,答案目前::

如果这是一个班级 Groovy, 那不是,你不能得到一个名字,但你必须将来能够做到这一点。

如果这是一个班级 Java, 编译下 Java 8, 你必须能够这样做。

也可以看看:

http://openjdk.java.net/jeps/118
https://docs.oracle.com/javase ... .html

对于每种方法,类似:


Whatever.declaredMethods
.findAll { !it.synthetic }
.collect { method ->
println method
method.name + " -> " + method.parameters.collect { "[$it.type : $it.name]" }.join/';'/
}
.each {
println it
}

小明明

赞同来自:

如果您正在使用 eclipse, 请参阅下面的图像,以便编译器可以存储有关该方法参数的信息

https://i.stack.imgur.com/RSLra.png

龙天

赞同来自:

如图所示 @Bozho, 如果在编译期间启用调试信息,则可以执行此操作。
这里有一个很好的答案......

https://coderoad.ru/2729580/
靠近
@AdamPaynter
..

.

使用库 ASM. 我带来了一个展示你如何实现目标的示例。

首先,开始 pom.xml 与这些依赖关系。


<dependency>
<groupid>org.ow2.asm</groupid>
<artifactid>asm-all</artifactid>
<version>5.2</version>
</dependency>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>4.12</version>
<scope>test</scope>
</dependency>


然后这个课程应该做你想做的事。 只需称之为静态方法
getParameterNames//

.


import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;

public class ArgumentReflection {
/**
* 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 theMethod
* @return
* @throws IOException
*/
public static List<string> getParameterNames/Method theMethod/ throws IOException {
Class<? > declaringClass = theMethod.getDeclaringClass//;
ClassLoader declaringClassLoader = declaringClass.getClassLoader//;

Type declaringType = Type.getType/declaringClass/;
String constructorDescriptor = Type.getMethodDescriptor/theMethod/;
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/theMethod.getName/// &amp;&amp; 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 = 1; i &lt;= argumentTypes.length; i++/ {
// The first local variable actually represents the "this"
// object if the method is not static!
parameterNames.add/localVariables.get/i/.name/;
}

return parameterNames;
}
}

return null;
}
}


以下是一个模块化测试的示例。


public class ArgumentReflectionTest {

@Test
public void shouldExtractTheNamesOfTheParameters3// throws NoSuchMethodException, SecurityException, IOException {

List<string> parameterNames = ArgumentReflection
.getParameterNames/Clazz.class.getMethod/"callMe", String.class, String.class//;
assertEquals/"firstName", parameterNames.get/0//;
assertEquals/"lastName", parameterNames.get/1//;
assertEquals/2, parameterNames.size///;

}

public static final class Clazz {

public void callMe/String firstName, String lastName/ {
}

}
}


您可以找到一个完整的示例
https://github.com/danidemi/po ... d-asm
注意

我改变了一点源解决方案 @AdamPaynter, 为了使它适用于方法。 如果我理解正确,其解决方案仅适用于设计人员。

该解决方案不适用于方法
static

. 这是由于在这种情况下,返回的参数数量 ASM, 不同,但这是可以容易地纠正的。
</string></localvariablenode></string></string></methodnode></string>

窦买办

赞同来自:

加入我的 2 美分; 参数信息在类文件中可用。 "for debugging", 当你使用时 javac-g 编译源。 它可供选择 APT, 但是你需要抽象,所以你不需要它。 /有人讨论了类似的东西 4-5 多年前在这里:
http://forums.java.net/jive/th ... t%3D0
/

简而言之,如果您不直接使用源文件,就无法获得它 /喜欢什么 APT 在汇编期间/.

君笑尘

赞同来自:

参数名称仅对编译器有用。 编译器创建类文件时,不包括参数名称 - 该方法的参数列表仅在其参数的类型中包含。 因此,通过反射来获得参数的名称是不可能的 /如您的问题所示/ - 它不存在任何地方。

但是,如果使用反射不是严格的要求,您可以直接从源代码中获取此信息。 /只要你有/.

要回复问题请先登录注册