Java基础知识(20)- Java 反射机制 (二) | 执行方法(访问方法)、访问数组、操作泛型(Generics)


1. 通过反射执行方法(访问方法)

    要动态获取一个对象方法的信息,首先需要通过下列方法之一创建一个 Method 类型的对象或者数组。

        getMethods()
        getMethods(String name,Class<?> …parameterTypes)
        getDeclaredMethods()
        getDeclaredMethods(String name,Class<?>...parameterTypes)

    如果是访问指定的构造方法,需要根据该方法的入口参数的类型来访问。例如,访问一个名称为 max,入口参数类型依次为 int 和 String 类型的方法。

    下面的两种方式均可以实现:

        objectClass.getDeclaredConstructor("max",int.class,String.class);
        objectClass.getDeclaredConstructor("max",new Class[]{int.class,String.class});

    Method 类的常用方法如表所示。

 

静态方法名称  说明
getName() 获取该方法的名称
getParameterType() 按照声明顺序以 Class 数组的形式返回该方法各个参数的类型
getReturnType() 以 Class 对象的形式获得该方法的返回值类型
getExceptionTypes() 以 Class 数组的形式获得该方法可能抛出的异常类型
invoke(Object obj,Object...args) 利用 args 参数执行指定对象 obj 中的该方法,返回值为 Object 类型
isVarArgs() 查看该方法是否允许带有可变数量的参数,如果允许返回 true,否则返回 false
getModifiers() 获得可以解析出该方法所采用修饰符的整数

 
    实例:

 1         import java.lang.reflect.Method;
 2 
 3         public class App {
 4             public static void main( String[] args ) {
 5 
 6                 // 通过反射执行方法(访问方法)
 7                 BookMethod bookMethod = new BookMethod();
 8                 Class bookMethodClass = bookMethod.getClass();
 9 
10                 Method[] declaredMethods = bookMethodClass.getDeclaredMethods();
11 
12                 for (int i = 0; i < declaredMethods.length; i++) {
13 
14                     Method method = declaredMethods[i];
15 
16                     System.out.println("方法名称 -> " + method.getName());
17 
18                     System.out.print("参数类型 -> ( ");
19                     Class[] parameterTypes = method.getParameterTypes();
20                     for (int j = 0; j < parameterTypes.length; j++) {
21                         System.out.print(parameterTypes[j]);
22                         if (j < parameterTypes.length-1)
23                             System.out.print(", ");
24                     }
25                     System.out.print(" )\n");
26 
27                     System.out.println("是否带可变数量参数 -> " + method.isVarArgs());
28                     System.out.println("返回值类型 -> " + method.getReturnType());
29 
30                     System.out.print("可能抛出的异常类型 -> ( ");
31 
32                     Class[]  methodExceptions = method.getExceptionTypes();
33                     for (int j = 0; j < methodExceptions.length; j++) {
34                         System.out.print(methodExceptions[j]);
35                         if (j < methodExceptions.length-1)
36                             System.out.print(", ");
37                     }
38                     System.out.print(" )\n");
39 
40                     // 方法的访问权限为 private,会拋出异常;
41                     // 或调用 setAccessible(true) 设置允许访问 private 成员
42                     //method.setAccessible(true);
43 
44                     try {
45                         if (method.getName().equals("publicMethod")) {
46                             System.out.println("publicMethod(1) = " + method.invoke(bookMethod, 1));
47                         } else if (method.getName().equals("protectedMethod")) {
48                             System.out.println("protectedMethod(\"3\", 8) = " + method.invoke(bookMethod, "3", 8));
49                         } else if (method.getName().equals("privateMethod")) {
50                             Object[] parameters = new Object[] { new String[] { "T", "E", "S", "T" } };
51                             System.out.println("privateMethod(...) = " + method.invoke(bookMethod, parameters));
52                         } else {
53                             method.invoke(bookMethod);
54                         }
55                     } catch (Exception e) {
56                         //e.printStackTrace();
57                         System.out.println("调用该方法失败:error -> " + e.getMessage());
58                     }
59 
60                     System.out.println("----------------------------------------------");
61                 }
62             }
63         }
64 
65         class BookMethod {
66 
67             // 默认访问权限方法
68             void defaultMethod() {
69                 System.out.println("执行 defaultMethod() 方法");
70             }
71 
72             // 默认访问权限 static 方法
73             static void defaultStaticMethod() {
74                 System.out.println("执行 defaultStaticMethod() 方法");
75             }
76 
77             // public 方法
78             public int publicMethod(int i) {
79                 System.out.println("执行 publicMethod() 方法");
80                 return 100 + i;
81             }
82 
83             // protected 方法
84             protected int protectedMethod(String s, int i) throws NumberFormatException {
85                 System.out.println("执行 protectedMethod() 方法");
86                 return Integer.valueOf(s) + i;
87             }
88 
89             // private 方法
90             private String privateMethod(String... args) {
91                 System.out.println("执行 privateMethod() 方法");
92                 StringBuffer sb = new StringBuffer();
93                 for (int i = 0; i < args.length; i++) {
94                     sb.append(args[i]);
95                 }
96                 return sb.toString();
97             }
98 
99         }


    输出:

        方法名称 -> privateMethod
        参数类型 -> ( class [Ljava.lang.String; )
        是否带可变数量参数 -> true
        返回值类型 -> class java.lang.String
        可能抛出的异常类型 -> (  )
        调用该方法失败:error -> Class com.example.ReflectionApp can not access a member of class com.example.BookMethod with modifiers "private transient"
        ----------------------------------------------
        方法名称 -> protectedMethod
        参数类型 -> ( class java.lang.String, int )
        是否带可变数量参数 -> false
        返回值类型 -> int
        可能抛出的异常类型 -> ( class java.lang.NumberFormatException )
        执行 protectedMethod() 方法
        protectedMethod("3", 8) = 11
        ----------------------------------------------
        方法名称 -> publicMethod
        参数类型 -> ( int )
        是否带可变数量参数 -> false
        返回值类型 -> int
        可能抛出的异常类型 -> (  )
        执行 publicMethod() 方法
        publicMethod(1) = 101
        ----------------------------------------------
        方法名称 -> defaultMethod
        参数类型 -> (  )
        是否带可变数量参数 -> false
        返回值类型 -> void
        可能抛出的异常类型 -> (  )
        执行 defaultMethod() 方法
        ----------------------------------------------
        方法名称 -> defaultStaticMethod
        参数类型 -> (  )
        是否带可变数量参数 -> false
        返回值类型 -> void
        可能抛出的异常类型 -> (  )
        执行 defaultStaticMethod() 方法


2. 通过反射访问数组

    java.lang.reflect.Array 类提供静态方法来动态创建和访问Java数组。

    实例:

 1        import java.lang.reflect.Field;
 2 
 3         public class App {
 4             public static void main( String[] args ) {
 5             
 6             // 通过反射访问数组
 7             Class<?> classType = null;
 8             Object newArray = null;
 9             try {
10                 classType = Class.forName("java.lang.String");
11                 newArray = Array.newInstance(classType, 3);
12             } catch (Exception e) {
13                 //e.printStackTrace();
14                 System.out.println("Create array instance failed:  " + e.getMessage());
15                 return;
16             }
17             Array.set(newArray, 0, "Country");
18             Array.set(newArray, 1, "Province");
19             Array.set(newArray, 2, "City");
20 
21             printArray(newArray);
22             printArray("It is string");
23             
24         }
25 
26         private static void printArray(Object obj) {
27             Class cls = obj.getClass();
28             // 判断是否是数组
29             if (cls.isArray()) {
30                 int arrLen = Array.getLength(obj);
31                 for (int i = 0; i < arrLen; i++){
32                     System.out.println("Array(" + cls.getComponentType().getName() + ") : " + Array.get(obj, i));
33                 }
34             }else {
35                 // 不是数组,直接输出
36                 System.out.println(obj);
37             }
38         }
39     }


    输出:

        Array(java.lang.String) : Country
        Array(java.lang.String) : Province
        Array(java.lang.String) : City
        It is string

3. 通过反射操作泛型(Generics)

    Java 5 开始增加了 ParameterizedType, GenericArrayType, TypeVariable 和 WildcardType 几种类型,在 java.lang.reflect 包。
  
        ParameterizedType: 表示一种参数化的类型,比如Collection< String >
        GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型
        TypeVariable: 是各种类型变量的公共父接口
        WildcardType: 代表一种通配符类型表达式,比如?、? extends Number、? super Integer。(wildcard是一个单词:就是”通配符“)

    实例:

 1         import java.lang.reflect.Method;
 2         import java.lang.reflect.ParameterizedType;
 3         import java.lang.reflect.Type;
 4         import java.util.List;
 5         import java.util.Map;
 6 
 7         public class App {  
 8             public static void main(String[] args) {
 9 
10                 try {
11                     // 获得指定方法参数泛型信息
12                     Method method = Demo.class.getMethod("testMethod01", Map.class, List.class);
13                     Type[] paramTypes = method.getGenericParameterTypes();
14 
15                     System.out.println("testMethod01() 的参数类型");
16                     for (Type t : paramTypes) {
17                         if(t instanceof ParameterizedType){
18                             Type[] genericTypes = ((ParameterizedType) t).getActualTypeArguments();
19                             for (Type genericType : genericTypes) {
20                                 System.out.println("参数类型 -> " + genericType);
21                             }
22                         }
23                     }
24 
25                     System.out.println("testMethod02() 的返回值类型");
26                     Method method2 = Demo.class.getMethod("testMethod02", null);
27                     Type returnType = method2.getGenericReturnType();
28                     if(returnType instanceof ParameterizedType){
29                         Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();
30 
31                         for (Type genericType : genericTypes) {
32                             System.out.println("返回值类型 -> "+genericType);
33                         }
34                     }
35 
36                 } catch (Exception e) {
37                     e.printStackTrace();
38                 }
39             }
40         }
41 
42         class Demo {
43 
44             public void testMethod01(Map<String, Demo> map, List<Demo> list){
45                 System.out.println("Demo.testMethod01()");
46             }
47 
48             public Map<Integer,Demo> testMethod02(){
49                 System.out.println("Demo.testMethod02()");
50                 return null;
51             }
52         }

 

    输出:

        testMethod01() 的参数类型
        参数类型 -> class java.lang.String
        参数类型 -> class com.example.Demo
        参数类型 -> class com.example.Demo
        testMethod02() 的返回值类型
        返回值类型 -> class java.lang.Integer
        返回值类型 -> class com.example.Demo
  

posted @ 2022-03-02 17:45  垄山小站  阅读(173)  评论(0)    收藏  举报