方法的参数名,在很多时候我们是需要反射得到的。但是在java8之前,代码编译为class文件后,方法参数的类型是固定的,但参数名称却丢失了,这和动态语言严重依赖参数名称形成了鲜明对比。(java是静态语言,所以入参名称叫什么其实无所谓的)。虽然名称无所谓,但很多时候,我们需要此名称来做更好的安排.

比如mybatis的Dao层接口方法,需要特意用个注解@Param来显示标识出参数名,当时写的时候我觉得挺傻X的一件事,所以java8来了,带来的新特性解决了这一问题

一. Parameter 类的定义

Parameter 类位于 java.lang.reflect 包中,主要用于在程序运行状态中,动态地获取参数信息

在 JDK8.0 之前,编译器会忽略我们编写代码时设定的参数名,因此会得到像 arg0、arg1 这样无意义的参数名,比如:当我们使用 mybatis 时,我们会用到 @Param 注解来使 mybatis 保留参数名称

在 JDK8.0 及之后,Java 在语言层面 (使用反射 API 和 Parameter.getName() 方法) 和字节码层面 (使用新的 javac 编译器以及 -parameters 参数) 提供了支持,不过为了保证向下兼容,在 JDK8.0 及之后的版本中该特性是默认关闭的

在 IDEA 中我们可以通过以下设置来完成
通过 Parameter 获取方法的参数信息 - 图1

如果使用了 maven,可以配置 maven 的编译插件

  1. <plugin>
  2. <groupId>org.apache.maven.plugins</groupId>
  3. <artifactId>maven-compiler-plugin</artifactId>
  4. <version>3.8.0</version>
  5. <configuration>
  6. <compilerArgument>-parameters</compilerArgument>
  7. <source>1.8</source>
  8. <target>1.8</target>
  9. </configuration>
  10. </plugin>

示例如下

  1. public class ParameterTest {
  2. public void test(String key, String value) {}
  3. public static void main(String[] args) throws Exception {
  4. Method method = ParameterTest.class.getMethod("test", String.class, String.class);
  5. Parameter[] parameters = method.getParameters();
  6. for (Parameter parameter : parameters) {
  7. // 正常编译得到: arg0 arg1
  8. // 加入-parameters后编译得到: key value
  9. System.out.println(parameter.getName());
  10. }
  11. }
  12. }

二. Parameter 类常用方法

getAnnotatedType()

  • 返回一个 AnnotatedType 对象,该对象表示使用类型来指定由该参数对象表示的形式参数的类型
  • 通过其 getType() 方法,我们可以获取到对应的形参类型 ```java public class ParameterTest {

    public void test(String key, String value) {}

    public static void main(String[] args) throws Exception {

    1. Method method = ParameterTest.class.getMethod("test", String.class, String.class);
    2. Parameter[] parameters = method.getParameters();
    3. for (Parameter parameter : parameters) {
    4. AnnotatedType annotatedType = parameter.getAnnotatedType();
    5. // class java.lang.String
    6. // class java.lang.String
    7. System.out.println(annotatedType.getType());
    8. }

    } }

  1. <a name="A3FzH"></a>
  2. ## getAnnotation(Class annotationClass)
  3. 如果该参数对象存在指定类型的注解,则返回该注解,否则返回 null
  4. 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotation() 方法与 getDeclaredAnnotation() 方法作用相同
  5. @Target(ElementType.PARAMETER)<br />@Retention(RetentionPolicy.RUNTIME)<br />public [@interface ]() ParameterAnnotation {

String key();

String value();

  1. }
  2. public class ParameterTest {

public void test(@ParameterAnnotation(key = “key”, value = “value”) String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); ParameterAnnotation annotation = parameters[0].getAnnotation(ParameterAnnotation.class); // @lang.reflect.Parameter.ParameterAnnotation(key=key, value=value) System.out.println(annotation); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />getDeclaredAnnotation(Class annotationClass)
  2. 如果该参数对象存在指定类型的注解,则返回该注解,否则返回 null
  3. 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotation() 方法与 getDeclaredAnnotation() 方法作用相同
  4. getAnnotationsByType(Class annotationClass)
  5. 如果该参数对象存在指定类型的注解,则返回该注解数组,否则返回 null
  6. 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同
  7. getAnnotationsByType() 方法与 getAnnotation() 方法的区别在于:getAnnotationsByType() 方法会检查修饰该参数对象的注解是否为可重复类型注解,如果是则会返回修饰该参数对象的一个或多个注解
  8. [@Repeatable ]() 用于声明注解为可重复类型注解
  9. 当声明为可重复类型注解后,如果参数注解仍为一个,则 getAnnotation() 方法会正常返回,如果参数注解为多个,则 getAnnotation() 方法会返回 null
  10. @Target(ElementType.PARAMETER)<br />@Retention(RetentionPolicy.RUNTIME)<br />// @Repeatable: 声明该注解为可重复类型注解<br />@Repeatable(RepeatableAnnotation.class)<br />public [@interface ]() ParameterAnnotation {

String key();

String value();

  1. }
  2. @Target(ElementType.PARAMETER)<br />@Retention(RetentionPolicy.RUNTIME)<br />[@interface ]() RepeatableAnnotation {<br />ParameterAnnotation[] value();<br />}
  3. public class ParameterTest {

public void test(@ParameterAnnotation(key = “key1”, value = “value1”) @ParameterAnnotation(key = “key2”, value = “value2”) String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); ParameterAnnotation annotation = parameters[0].getAnnotation(ParameterAnnotation.class); // null System.out.println(parameters[0].getAnnotation(ParameterAnnotation.class)); ParameterAnnotation[] annotationsByType = parameters[0].getAnnotationsByType(ParameterAnnotation.class); // [@lang.reflect.ParameterAnnotation(key=key1, value=value1), @lang.reflect.ParameterAnnotation(key=key2, value=value2)] System.out.println(Arrays.toString(annotationsByType)); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />getDeclaredAnnotationsByType(Class annotationClass)
  2. 如果该参数对象存在指定类型的注解,则返回该注解数组,否则返回null
  3. 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同
  4. getAnnotations()
  5. 返回该参数对象上的所有注解,如果没有注解,则返回空数组
  6. 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotations() 方法与 getDeclaredAnnotations() 方法作用相同
  7. @Target(ElementType.PARAMETER)<br />@Retention(RetentionPolicy.RUNTIME)<br />public [@interface ]() ParameterAnnotation {

String key();

String value();

  1. }
  2. @Target(ElementType.PARAMETER)<br />@Retention(RetentionPolicy.RUNTIME)<br />public [@interface ]() TestAnnotation {

String key();

String value();

  1. }
  2. public class ParameterTest {

public void test(@ParameterAnnotation(key = “key1”, value = “value1”) @TestAnnotation(key = “key2”, value = “value2”) String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); Annotation[] annotations = parameters[0].getAnnotations(); // [@lang.reflect.ParameterAnnotation(key=key1, value=value1), @lang.reflect.TestAnnotation(key=key2, value=value2)] System.out.println(Arrays.toString(annotations)); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />getDeclaredAnnotations()
  2. 返回该参数对象上的所有注解,如果没有注解,则返回空数组
  3. 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotations() 方法与 getDeclaredAnnotations() 方法作用相同
  4. getModifiers()
  5. 返回修饰该参数对象修饰符的整数形式,使用 Modifier 类对其进行解码
  6. public class ParameterTest {

public void test(final String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); // final System.out.println(Modifier.toString(parameters[0].getModifiers())); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />getName()
  2. 返回参数对象名称
  3. public class ParameterTest {

public void test(String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); for (Parameter parameter : parameters) { // 正常编译得到: arg0 arg1 // 加入-parameters后编译得到: key value System.out.println(parameter.getName()); } }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />getParameterizedType()
  2. 返回一个类型对象,该对象表示该参数对象表示的泛型参数的类型 (保留泛型)
  3. public class ParameterTest {

public void test(T t, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, Object.class, String.class); Parameter[] parameters = method.getParameters(); // T System.out.println(parameters[0].getParameterizedType().getTypeName()); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />getType()
  2. 返回一个 Class 对象,该 Class 对象表示该参数对象表示的声明参数的类型 (擦除泛型)
  3. public class ParameterTest {

public void test(T t, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, Object.class, String.class); Parameter[] parameters = method.getParameters(); // class java.lang.Object System.out.println(parameters[0].getType()); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />isAnnotationPresent(Class<? extends Annotation> annotationClass)
  2. 如果该参数对象上有指定类型的注解,则返回 true,否则为 false
  3. public class ParameterTest {

public void test(@ParameterAnnotation(key = “key”, value = “value”) String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); // true System.out.println(parameters[0].isAnnotationPresent(ParameterAnnotation.class)); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />如果该参数对象上的注解类型为可重复类型注解,则需要标明可重复注解而不是其子注解,才会返回 true,否则为 false
  2. @Target(ElementType.PARAMETER)<br />@Retention(RetentionPolicy.RUNTIME)<br />@Repeatable(RepeatableAnnotation.class)<br />public [@interface ]() ParameterAnnotation {

String key();

String value();

  1. }
  2. @Target(ElementType.PARAMETER)<br />@Retention(RetentionPolicy.RUNTIME)<br />[@interface ]() RepeatableAnnotation {<br />ParameterAnnotation[] value();<br />}
  3. public class ParameterTest {

public void test(@ParameterAnnotation(key = “key1”, value = “value1”) @ParameterAnnotation(key = “key2”, value = “value2”) final String key, String value) { }

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); // false System.out.println(parameters[0].isAnnotationPresent(ParameterAnnotation.class)); // true System.out.println(parameters[0].isAnnotationPresent(RepeatableAnnotation.class)); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />isVarArgs()
  2. 如果该参数对象表示 可变参,则返回 true,否则为 false
  3. public class ParameterTest {

public void test(String key, String … values) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String[].class); Parameter[] parameters = method.getParameters(); // false System.out.println(parameters[0].isVarArgs()); // true System.out.println(parameters[1].isVarArgs()); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />isNamePresent()
  2. 如果该参数对象根据类文件能获取到名称,则返回 true,否则为 false
  3. 当我们带上 -parameters 参数时,该参数对象就有了名称
  4. public class ParameterTest {

public void test(String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); // 正常编译得到: false arg0 // 加入-parameters 后编译得到: true key System.out.println(parameters[0].isNamePresent() + “ “ + parameters[0].getName()); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />getDeclaringExecutable()
  2. 返回声明该参数对象的可执行文件
  3. public class ParameterTest {

public void test(String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); // public void lang.reflect.ParameterTest.test(java.lang.String,java.lang.String) System.out.println(parameters[0].getDeclaringExecutable()); }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />isImplicit()
  2. 如果该参数对象为隐式参数,则返回 true,否则为 false
  3. Java 编译器会为内部类的构造方法创建一个隐式参数
  4. public class ParameterTest {

class InnerClass {

  1. public InnerClass(String key) {
  2. }

}

public static void main(String[] args) throws Exception { Constructor declaredConstructor = InnerClass.class.getConstructor(ParameterTest.class, String.class); Parameter[] parameters = declaredConstructor.getParameters(); for (Parameter parameter : parameters) { // 【final lang.reflect.ParameterTest this$0】 isImplicit() ===> true // 【java.lang.String key】 isImplicit() ===> false System.out.println(“【” + parameter + “】 isImplicit() ===> “ + parameter.isImplicit()); } }

  1. }<br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />isSynthetic()
  2. 如果该参数对象为合成参数,则返回 true,否则为 false
  3. public class ParameterTest {

public void test(String key, String value) {}

public static void main(String[] args) throws Exception { Method method = ParameterTest.class.getMethod(“test”, String.class, String.class); Parameter[] parameters = method.getParameters(); // false System.out.println(parameters[0].isSynthetic()); } ```