返回

认识哈Java反射机制

Java’s One…

0x01

何为反射

正向

  • 导入类包(import)
  • 实例化对象(new)
  • 调用属性(object.field_name)
  • 调用方法(object.method_name)

反向 与正向相对应调用

  • java.lang.Class
  • java.lang.reflect.Constructor
  • java.lang.reflect.Field
  • java.lang.reflect.Method

反射不需要有明确的类型对象,使用Object表示即可。

java.lang.Class

内部可以记录类的成员、接口等信息,其为一个表示类的类。

类定义:

public final class Class<T>
extends Object
implements Serializable, GenericDeclaration, Type, AnnotatedElement

获取Class类。

  1. public final Class<?> getClass()
  2. 使用类名.class
  3. 1. public static Class<?> forName(String className) throws ClassNotFoundExceptio

第二种多用于程序开发,第三种多用框架设计,为反射机制使用的方法。

forName后续

  • 实例化对象
public T newInstance() throws InstantiationException,IllegalAccessException

这是一个Class类的一个无参构造方法,也就会调用所表示类的无参构造方法,返回一个Class所表示的类的实例。

  • 获取类中构造方法
  1. public Constructor<?>[] getConstructors()throws SecurityException

  2. public Constructor<T> getConstructor(Class<?>... parameterTypes)throws NoSuchMethodException,SecurityException

返回java.lang.reflect.Constructor类

Demo:

public static void main(String[] args) throws ClassNotFoundException {
        Class<?> cls = Class.forName("java.lang.String");

        Constructor<?>[] cons = cls.getConstructors();

        for (int i = 0; i < cons.length; i++) {
            System.out.println(cons[i]);
        }
    }

Show:

public java.lang.String(byte[],int,int)
public java.lang.String(byte[],java.nio.charset.Charset)
public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int,int,java.nio.charset.Charset)
public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(java.lang.StringBuilder)
public java.lang.String(java.lang.StringBuffer)
public java.lang.String(byte[])
public java.lang.String(int[],int,int)
public java.lang.String()
public java.lang.String(char[])
public java.lang.String(java.lang.String)
public java.lang.String(char[],int,int)
public java.lang.String(byte[],int)
public java.lang.String(byte[],int,int,int)

关于Class有参构造函数

函数定义:

public T newInstance(Object... initargs)throws InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException

有参构造函数调用Demo:

class Student {
    private String name;

    private Integer age;

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "name:" + this.name + ";age:" + this.age;
    }
}

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("com.test.Student");

        Constructor<?> con = cls.getConstructor(String.class, Integer.class);

        Object stu = con.newInstance("idlefire", 21);
        System.out.println(stu);
    }
}

Show:

name:idlefire;age:21

Class类调用无参构造,Constructor类调用有参构造方法

  • 获取类中方法

获取父类以及本类全部方法

  1. public Method[] getMethods()throws SecurityException

获取父类指定方法

  1. public Method getMethod(String name,Class<?>... parameterTypes)throws NoSuchMethodException,SecurityException

获取本类全部方法

  1. public Method[] getDeclaredMethods()throws SecurityException

获取本类指定方法

  1. public Method getDeclaredMethod(String name,Class<?>... parameterTypes)throwsNoSuchMethodException,SecurityException

String name 指定是方法名

  • 反射中的invoke方法

方法定义:

public Object invoke(Object obj,Object... args)throws IllegalAccessException,IllegalArgumentException,InvocationTargetException

利用上面获取的Method对象,当该对象调用invoke方法时,相当与从指定对象中调用该Method所代表的方法。

Demo:

public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("com.test.Student4");

        Object obj = cls.newInstance();

        Method setnameMethod = cls.getMethod("setName", String.class);

        Method getnameMethod = cls.getMethod("getName");

        setnameMethod.invoke(obj, "idlefire");

        System.out.println(getnameMethod.invoke(obj));

    }


class Student4 {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Show:

  • 利用反射调用类中属性

包含继承类 获取全部属性

  1. public Field[] getFields() throws SecurityException

获取指定属性

  1. public Field getField(String name)throwsNoSuchFieldException,SecurityException

仅限于本类 获取全部属性

  1. public Field[] getDeclaredFields()throws SecurityException

获取指定属性

  1. public Field getDeclaredField(String name)throws NoSuchFieldException,SecurityException

设置和获取属性

public void set(Object obj,
                Object value)
         throws IllegalArgumentException,
                IllegalAccessException
...
public Object get(Object obj)
           throws IllegalArgumentException,
                  IllegalAccessException

Demo:

class Student5 {

    private String name;

}
...
public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("com.test.Student5");

        Object obj = cls.newInstance();

        Field namefield = cls.getDeclaredField("name");

        namefield.setAccessible(true);

        namefield.set(obj, "idlefire");

        System.out.println(namefield.get(obj));

    }
}

其中setAccessible方法是为了能够访问非公开的属性,在Construction,Method,Field三个类中有一个共同的父类AccessibleObject,定义了取消封装的操作:setAccessible(Boolean flag)。

未使用setAccessible:

(ง •_•)ง