• 反射之获取方法


     1 import java.lang.reflect.*;
     2 public class Demo12{
     3     
     4     /*
     5     通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method:
     6     
     7     Method getMethod(name, Class...):获取某个public的Method(包括父类)
     8     Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
     9     Method[] getMethods():获取所有public的Method(包括父类)
    10     Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
    11     */
    12     
    13     //reflection反射
    14     public static void main(String[] args) throws Exception{  //记住要抛出异常
    15         Class stdClass = Student.class;
    16         //获取public方法getScore,参数为String
    17         System.out.println(stdClass.getMethod("getScore",String.class));
    18         //获取继承的public方法getName,无参数
    19         System.out.println(stdClass.getMethod("getName"));
    20         //获取private方法getGrade,参数为int
    21         System.out.println(stdClass.getDeclaredMethod("getGrade",int.class));
    22         
    23     }
    24 }
    25 
    26 class Student extends Person {
    27     public int getScore(String type) {
    28         return 99;
    29     }
    30     private int getGrade(int year) {
    31         return 1;
    32     }
    33 }
    34 
    35 class Person {
    36     public String getName() {
    37         return "Person";
    38     }
    39 }

    一个Method对象包含一个方法的所有信息:

    • getName():返回方法名称,例如:"getScore"
    • getReturnType():返回方法返回值类型,也是一个Class实例,例如:String.class
    • getParameterTypes():返回方法的参数类型,是一个Class数组,例如:{String.class, int.class}
    • getModifiers():返回方法的修饰符,它是一个int,不同的bit表示不同的含义。

    调用方法

    当我们获取到一个Method对象时,就可以对它进行调用。

    如果用反射来调用substring方法,参考以下代码:

     1 import java.lang.reflect.*;
     2 public class Demo12{
     3     
     4     /*
     5     通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method:
     6     
     7     Method getMethod(name, Class...):获取某个public的Method(包括父类)
     8     Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
     9     Method[] getMethods():获取所有public的Method(包括父类)
    10     Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
    11     */
    12     
    13     //reflection反射
    14     public static void main(String[] args) throws Exception{  //记住要抛出异常
    15         String s = "Hello world";
    16         //获取子串
    17         System.out.println(s.substring(6)); //world
    18         System.out.println("****************");
    19         //获取String对象的substring(int,int)方法,参数为int,int
    20         Method m = s.getClass().getMethod("substring",int.class,int.class);
    21         //查看一下
    22         System.out.println(m);
    23         //在s对象上调用该方法并获取结果
    24         String r = (String)m.invoke(s,6,9);
    25         System.out.println(r);//wor
    26     }
    27 }

     注意到substring()有两个重载方法,我们获取的是String substring(int,int)这个方法

    Method实例调用invoke就相当于调用该方法,invoke的第一个参数是对象实例,即在哪个实例上调用该方法,后面的可变参数要与方法参数一致,否则将报错

    调用静态方法

    如果获取到的Method表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以invoke方法传入的第一个参数永远为null。我们以Integer.parseInt(String)为例:

     1 import java.lang.reflect.*;
     2 public class Demo12{
     3     
     4     /*
     5     通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method:
     6     
     7     Method getMethod(name, Class...):获取某个public的Method(包括父类)
     8     Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
     9     Method[] getMethods():获取所有public的Method(包括父类)
    10     Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
    11     */
    12     
    13     //reflection反射
    14     public static void main(String[] args) throws Exception{  //记住要抛出异常
    15         //获取Integer的Class对象
    16         Class cls = Integer.class;
    17         //获取Integer的静态方法parseInt
    18         Method m = cls.getMethod("parseInt",String.class);
    19         // 调用该静态方法并获取结果:
    20         Integer n = (Integer)m.invoke(null,"123");
    21         System.out.println(n);    //123
    22     }
    23 }

    调用非public方法

    和Field类似,对于非public方法,我们虽然可以通过Class.getDeclaredMethod()获取该方法实例,但直接对其调用将得到一个IllegalAccessException。为了调用非public方法,我们通过Method.setAccessible(true)允许其调用:

     1 import java.lang.reflect.*;
     2 public class Demo12{
     3     
     4     /*
     5     通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method:
     6     
     7     Method getMethod(name, Class...):获取某个public的Method(包括父类)
     8     Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
     9     Method[] getMethods():获取所有public的Method(包括父类)
    10     Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
    11     */
    12     
    13     //reflection反射
    14     public static void main(String[] args) throws Exception{  //记住要抛出异常
    15         Person p = new Person();
    16         //获取Person的Class对象
    17         Class cls = p.getClass();
    18         //获取setNamef方法的Method对象
    19         Method m = cls.getDeclaredMethod("setName",String.class);
    20         //private修饰的方法,需要设置开启访问权限
    21         m.setAccessible(true);
    22         //调用setName(String)方法
    23         m.invoke(p,"2020年1月4日");
    24         //查看一下name字段值
    25         System.out.println(p.name);
    26     }
    27 }
    28 
    29 class Person {
    30     String name;
    31     private void setName(String name) {
    32         this.name = name;
    33     }
    34 }

    此外,setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对javajavax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全

    多态

    我们来考察这样一种情况:一个Person类定义了hello()方法,并且它的子类Student也覆写了hello()方法,那么下面程序,调用的方法到底是哪个?

     1 import java.lang.reflect.*;
     2 public class Demo12{
     3     
     4     /*
     5     通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method:
     6     
     7     Method getMethod(name, Class...):获取某个public的Method(包括父类)
     8     Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
     9     Method[] getMethods():获取所有public的Method(包括父类)
    10     Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
    11     */
    12     
    13     //reflection反射
    14     public static void main(String[] args) throws Exception{  //记住要抛出异常
    15         Person p = new Student();
    16         //获取Person的Class对象
    17         Class cls = p.getClass();
    18         //获取setNamef方法的Method对象
    19         Method m = cls.getMethod("hello");
    20         //调用hello方法,会打印什么呢?
    21         m.invoke(p);
    22     }
    23 }
    24 
    25 class Person {
    26     public void hello() {
    27         System.out.println("Person:hello");
    28     }
    29 }
    30 
    31 class Student extends Person {
    32     public void hello() {
    33         System.out.println("Student:hello");
    34     }
    35 }

     运行上述代码,发现打印出的是Student:hello,因此,使用反射调用方法时,仍然遵循多态原则:即总是调用实际类型的覆写方法(如果存在)

    小结

    Java的反射API提供的Method对象封装了方法的所有信息:

    通过Class实例的方法可以获取Method实例:getMethod()getMethods()getDeclaredMethod()getDeclaredMethods()

    通过Method实例可以获取方法信息:getName()getReturnType()getParameterTypes()getModifiers()

    通过Method实例可以调用某个对象的方法:Object invoke(Object instance, Object... parameters)

    通过设置setAccessible(true)来访问非public方法;

    通过反射调用方法时,仍然遵循多态原则。

  • 相关阅读:
    自我介绍+软工5问
    团队展示&选题
    团队展示&选题 (白衣天使队)
    结对编程(-java-实现)
    个人项目wc(Java)
    自我介绍+软工五问
    软件工程结课作业
    第四次博客作业-结对项目
    软件工程第三次作业——关于软件质量保障初探
    20194613 自动生成四则运算第一版报告
  • 原文地址:https://www.cnblogs.com/zui-ai-java/p/14230994.html
Copyright © 2020-2023  润新知