反射第三弹。

Java反射(Reflection)(三)

1. 通过Class获取Method的几个方法

  • Method getDeclaredMethod(String name, Class<?>… parameterTypes)

    返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 
  • Method[] getDeclaredMethods()

    返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但`不包括继承`的方法。 
  • Method getMethod(String name, Class<?>… parameterTypes)

    返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 
  • Method[] getMethods()

    返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(`包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口`)的公共 member 方法 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    package top.tobing.reflection;
    import java.lang.reflect.Method;
    /**
    * 反射之方法
    * @author Tobing
    */
    public class Demo05ReflectMethod1 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
    Class cls = Boy.class;
    //Method methodA = cls.getMethod("privateMethod");// java.lang.NoSuchMethodException
    //Method methodD = cls.getDeclaredMethod("eat"); // java.lang.NoSuchMethodException
    Method methodB = cls.getDeclaredMethod("privateMethod"); // 可以获取私有方法,但不可以获取父类方法
    Method methodC = cls.getDeclaredMethod("publicMethodA");
    Method methodE = cls.getMethod("eat"); // 可以获取父类私有方法,但不可以获取私有方法
    System.out.println(methodB.getName());
    System.out.println(methodC.getName());
    System.out.println(methodE.getName());
    Method methods[] = cls.getMethods();

    System.out.println("======================================");
    System.out.println("Boy的所有方法(包含父类继承的):");
    for(Method m:methods) {
    System.out.println("getMethods:"+m.getName());
    }
    System.out.println("======================================");
    Method methods1[] = cls.getDeclaredMethods();
    for(Method m:methods1) {
    System.out.println("getDeclaredMethods:"+m.getName());
    }

    }
    }

    /*
    Method getMethod(name, Class...):获取某个public的Method(包括父类)
    Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
    Method[] getMethods():获取所有public的Method(包括父类)
    Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
    */

    class P{
    public void eat(){
    System.out.println("This is p's eat!");
    }
    }


    class Boy extends P{
    public void publicMethodA() {
    System.out.println("This is a public method A !");
    }

    public void publicMethodB() {
    System.out.println("This is a public method B !");
    }

    private void privateMethod() {
    System.out.println("This is a privateMethod!");
    }
    }
  • 运行结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    privateMethod
    publicMethodA
    eat
    ======================================
    Boy的所有方法(包含父类继承的):
    getMethods:publicMethodB
    getMethods:publicMethodA
    getMethods:eat
    getMethods:wait
    getMethods:wait
    getMethods:wait
    getMethods:equals
    getMethods:toString
    getMethods:hashCode
    getMethods:getClass
    getMethods:notify
    getMethods:notifyAll
    ======================================
    getDeclaredMethods:privateMethod
    getDeclaredMethods:publicMethodB
    getDeclaredMethods:publicMethodA

  • 执行指定对象的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package top.tobing.reflection;

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;

    /**
    * 反射之方法
    * @author Tobing
    */
    public class Demo05ReflectMethod2 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    Class cls = Boy.class;
    Method methodB = cls.getDeclaredMethod("privateMethod"); // 可以获取私有方法,但不可以获取父类方法
    Method methodC = cls.getDeclaredMethod("publicMethodA");
    Method methodE = cls.getMethod("eat");
    Boy b = new Boy();
    //methodB.invoke(b); // cannot access a member of class top.tobing.reflection.Boy with modifiers "private"
    methodE.invoke(b);
    methodC.invoke(b);

    }
    }

  • 运行结果

    1
    2
    This is p's eat!
    This is a public method A !
  • 要想执行对象中的private方法,可以使用methodObj.setAccessible(true);来设置其是否可被访问

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

    1
    2
    methodB.setAccessible(true);  // 设置private方法的访问属性
    methodB.invoke(b); // 执行方法
  • 使用invoke调用静态方法

    1
    2
    3
    4
    5
    6
    7
    // 使用invoke调用静态方法
    int temp = Integer.parseInt("123"); // 以下代码等同于这一句话
    //1.获取Integer的字节码对象,通过字节码对象获取到方法 getMethod(方法名称,方法的参数列表)
    Method methodA = Integer.class.getMethod("parseInt",String.class);
    //2.通过invoke执行方法 invoke(执行方法所在的对象,执行方法需要的参数(不限个数))
    Object obj = methodA.invoke(null,"123");
    System.out.println(obj);

2. 调用构造方法(创建实例)

  • 在Class类中提供了一个newInstance方法用来创建对象的实例

    1
    2
    Person p = new Person();	// 这两件代码都可以用于新建对象实例
    Person p = Person.class.newInstance();
    • 但是newInstance方法也有弊端:只能实例化带public修饰的空参数构造方法
  • 为了解决以上缺陷,java的reflect的API提供Constructor对象,包含了构造方法的所有信息,可用于创建实例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    package top.tobing.reflection;

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;

    /**
    * 反射之方法
    * @author Tobing
    */
    public class Demo06ReflectMethod4 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
    // 方式一:使用newInstance()(不可以获取带参数)
    C c = C.class.newInstance();
    // 方式二:获取Constructor类(可以获取带参数)
    // 不可以获取到非public
    Constructor con1 = C.class.getConstructor();
    Constructor con2 = C.class.getConstructor(Integer.class);
    // 可以获取到非public构造方法
    Constructor con3 = C.class.getDeclaredConstructor(String.class);
    // 使用Constructor类的newInstance方法
    C c1= (C)con1.newInstance(); //调用空参数构造方法
    C c2 = (C)con2.newInstance(12); //低氧
    C c3 = (C)con3.newInstance("Tobing");

    }
    }

    class C{
    private String name;
    private int id;
    public C() {
    System.out.println("空参数public构造方法被调用了!!!");
    }

    public C(Integer id) {
    System.out.println("带参数public构造方法被调用了!!!");
    }

    C (String name){
    this.name = name;
    System.out.println("带参数非public的构造方法执行了!!!");
    }

    }
  • 运行结果

    1
    2
    3
    4
    5
    空参数public构造方法被调用了!!!
    空参数public构造方法被调用了!!!
    带参数public构造方法被调用了!!!
    带参数非public的构造方法执行了!!!

3. 获取继承关系

  1. 获取父类Class

  2. 获取interface

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package top.tobing.reflection;

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;

    /**
    * 反射之方法
    * @author Tobing
    */
    public class Demo07ReflectInherit {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
    Class cls1 = Integer.class;

    // 获取相关父类
    Class cls2 = cls1.getSuperclass();
    Class cls3 = cls2.getSuperclass();

    System.out.println("Integer's super class is :"+cls2.getName());
    System.out.println("Number's super class is :"+cls3.getName());
    System.out.println("Object's super class is :"+cls3.getSuperclass());

    // 获取interface
    Class[] interfaces = cls1.getInterfaces();
    for(Class c:interfaces) {
    System.out.println(c.getName());
    }
    }
    }
  • 输出

    1
    2
    3
    4
    5
    Integer's super  class is :java.lang.Number
    Number's super class is :java.lang.Object
    Object's super class is :null
    java.lang.Comparable

4. 动态代理

  • 如果根据字节码的创建时机来分类,可以分为静态代理和动态代理:

    • 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。
    • 而动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件
  • 由于学识尚浅,未能详尽。

评论