Bootstrap

Java的java.lang.reflect.Method应用

记录:481

场景:java.lang.reflect.Method的使用,包括但不限于创建Method对象,使用Method对象的invoke方法调用类方法,使用Method对象获取方法上的注解,以及其它常用方式使用。在Java反射机制中发挥重要作用。

版本:JDK 1.8,Spring Boot 2.6.3。

1.基础

1.1Method

在JDK的java.lang.reflect.Method中对Method的官方说明如下:

A Method provides information about, and access to, a single method on a class or interface. The reflected method may be a class method or an instance method (including an abstract method).

A Method permits widening conversions to occur when matching the actual parameters to invoke with the underlying method's formal parameters, but it throws an IllegalArgumentException if a narrowing conversion would occur.

1.2Java 反射机制

Java 反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法。这种在运行时动态的获取信息以及动态调用对象的方法的功能称为Java 的反射机制。

2.创建Method对象

使用类的Class对象获取该类的Method对象。public修饰的方法使用getMethod和getMethods获取Method对象。使用getDeclaredMethod和getDeclaredMethods获取类所有声明的方法的Method对象。

Class<?> clz01 = Worker.class;
//1.获取类的方法(public修饰的方法)
Method[] method01 = clz01.getMethods();
Method method02 = clz01.getMethod("getCityInfo", String.class);
StringBuilder sb01 = new StringBuilder();
Arrays.asList(method01).forEach(item -> {
    sb01.append(item.getName() + ",");
});
System.out.println("method01方法列表: " + sb01.toString());
System.out.println("method02方法名称: " + method02.getName());
//2.获取类的声明方法(public/protected/private)
Method[] method03 = clz01.getDeclaredMethods();
Method method04 = clz01.getDeclaredMethod("getCountryInfo", String.class);
StringBuilder sb02 = new StringBuilder();
Arrays.asList(method03).forEach(item -> {
    sb02.append(item.getName() + ",");
});
System.out.println("method03方法列表: " + sb02.toString());
System.out.println("method04方法名称: " + method04.getName());
//3.获取类的闭合方法
Class<?> clz02 = (new FujianProvince01()).work().getClass();
Method method05 = clz02.getEnclosingMethod();

3.使用Method对象的invoke方法调用类方法

使用Method对象的invoke方法调用类方法。在反射中就是使用此方法。

Class<?> clz03 = Worker.class;
//1.使用Method对象调用类的private修饰的方法(需设置允许访问)
Method method06 = clz03.getDeclaredMethod("getCountryInfo", String.class);
method06.setAccessible(true);
Object obj01 = method06.invoke(clz03.newInstance(), "中国");
System.out.println("obj01 = " + obj01.toString());
//2.使用Method对象调用类的protected修饰的方法(需设置允许访问)
Method method07 = clz03.getDeclaredMethod("getProvinceInfo", String.class);
method07.setAccessible(true);
Object obj02 = method07.invoke(clz03.newInstance(), "350000");
System.out.println("obj02 = " + obj02.toString());
//3.使用Method对象调用类的public修饰的方法
Method method08 = clz03.getDeclaredMethod("getCityInfo", String.class);
Object obj03 = method08.invoke(clz03.newInstance(), "350200");
System.out.println("obj03 = " + obj03.toString());
//4.使用Method对象调用类的public修饰的方法
Method method09 = clz03.getDeclaredMethod("getDistrictInfo", String.class);
Object obj04 = method09.invoke(clz03.newInstance(), "350203");
System.out.println("obj04 = " + obj04.toString());

4.使用Method对象获取方法上的注解

使用Method对象获取方法上的注解,在反射编程和面向切片编程时,起到重要作用:

Class<?> clz04 = Worker.class;
Method method10 = clz04.getDeclaredMethod("getDistrictName", String.class);
Annotation anno01 = method10.getAnnotation(DistrictMethodAno.class);
Annotation[] anno02 = method10.getAnnotations();
Annotation anno03 = method10.getDeclaredAnnotation(DistrictMethodAno.class);
Annotation[] anno04 = method10.getDeclaredAnnotations();
Annotation[][] anno05 = method10.getParameterAnnotations();
Annotation[] anno06 = method10.getAnnotationsByType(DistrictMethodAno.class);
AnnotatedType anno07 = method10.getAnnotatedReceiverType();
AnnotatedType[] anno08 = method10.getAnnotatedParameterTypes();
AnnotatedType anno09 = method10.getAnnotatedReturnType();
AnnotatedType[] anno10 = method10.getAnnotatedExceptionTypes();
Annotation[] anno11 = method10.getDeclaredAnnotationsByType(DistrictMethodAno.class);

5.其它常用方法

Class<?> clz05 = Worker.class;
Method method11 = clz04.getDeclaredMethod("getCityInfo", String.class);
//获取方法名称
String name01 = method11.getName();
//获取Modifier
int mod01 = method11.getModifiers();
//参数类型
TypeVariable<Method>[] type01 = method11.getTypeParameters();
//返回值类型
Class<?> clz06 = method11.getReturnType();
Type type02 = method11.getGenericReturnType();
//参数类型
Class<?>[] clz07 = method11.getParameterTypes();
//参数个数
int num01 = method11.getParameterCount();
//参数类型
Type[] type03 = method11.getGenericParameterTypes();
//异常类型
Class<?>[] clz08 = method11.getExceptionTypes();
Type[] type04 = method11.getGenericExceptionTypes();
//Hash编码
int num02 = method11.hashCode();
//判断方法
boolean bl01 = method11.isBridge();
boolean bl02 = method11.isVarArgs();
boolean bl03 = method11.isSynthetic();
boolean bl04 = method11.isDefault();
Object obj05 = method11.getDefaultValue();

6.辅助类

6.1DistrictMethodAno注解

注解DistrictMethodAno作用在方法上。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DistrictMethodAno {
    //区编码
    String code();
    //区名称
    String value() default "";
}

6.2ReturnAno注解

作用在返回值上的注解。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReturnAno {
}

6.3ParameterAno注解

作用在参数上的注解。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface ParameterAno {
    //参数编码
    String code();
    //参数名称
    String value() default "";
}

6.4Worker测试类

在Worker中定义了几种类型方法,使用Method对象调用。

public class Worker {
  public String name;
  private String getCountryInfo(String name) {
      if (StringUtils.equals("中国", name))
          return "中国是一个了不起的国家";
      return "请检查输入的国名";
  }
  protected String getProvinceInfo(String code) {
      if (StringUtils.equals("350000", code))
          return "福建是一个沿海省";
      return "请检查省级行政区编码";
  }
  public String getCityInfo(String code) {
      if (StringUtils.equals("350200", code))
          return "厦门是一个美丽城市";
      return "请检查市级行政区编码";
  }
  public static String getDistrictInfo(String code) {
      if (StringUtils.equals("350203", code))
          return "思明区在厦门岛内";
      return "请检查区级行政区编码";
  }
  @DistrictMethodAno(code = "Haicang",value = "海沧区")
  public  @ReturnAno String getDistrictName(@ParameterAno(code = "01",value = "区名称") String code) {
      if (StringUtils.equals("350205", code))
          return "海沧区";
      return "请检查区级行政区编码";
  }
}

6.5FujianProvince01测试类

在FujianProvince01的方法中定义了类。

public class FujianProvince01 {
  public Object city;
  //构造方法内定义类
  public FujianProvince01() {
      class Xiamen {
          public String cityNo;
          public String cityName;
      }
      city = new Xiamen();
  }
  //方法内定义类
  public Object work() {
      class Haicang {
          public String cityNo = "350203";
          public String cityName = "思明区";
          public String getDistrictInfo(String code) {
              if (StringUtils.equals(cityNo, code))
                  return cityName + "在厦门岛内";
              return "请检查区级行政区编码";
          }
      }
      return new Haicang();
  }
}

以上,感谢。

2024年3月1日

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;