[Android] [Reflexión] Mecanismo de reflexión

Introducción a la clase

La clase Class es muy especial. No tiene un método de construcción común. Es llamada por jvm (comprensión simple: nuevo objeto o cuando es cargada por el cargador de clases). En Java, cada clase tiene un objeto Class correspondiente. En otras palabras, cuando escribimos una clase, una vez completada la compilación, se generará un objeto Class en el archivo .class generado para representar la información de tipo de esta clase.

Todos los tipos en Java, incluidos los tipos básicos como int y float, tienen objetos Class relacionados con ellos. Si conoce el nombre de la clase correspondiente, se puede Class.forName()construir el objeto de la clase correspondiente, si no hay una clase correspondiente, o no se carga en, arroja el objeto ClassNotFoundException.

Método de adquisición de clases

  • Utilice el objeto para llamar al método getClass () para obtener la instancia Class del objeto;
  • Utilice el método estático forName () de la clase Class para obtener una instancia de Class por el nombre de la clase;
  • Use el método de .class para obtener la instancia de Class. Para la clase de paquete del tipo de datos básico, también puede usar .TYPE para obtener la instancia de Class del tipo de datos básico correspondiente;

Puede ver el ejemplo de código a continuación:

    //方式一
    Person person = new Person();
    Class<? extends Person> personClazz01 = person.getClass();
 
    //方式二
    try {
        Class<?> personClazz02 = Class.forName("Person");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
 
    //方式三
    Class<? extends Person> personClazz03 = Person.class;

Recordatorio amistoso: Durante la operación, si queremos generar un objeto de una determinada clase, la Máquina Virtual Java (JVM) comprobará si se ha cargado el objeto Class de este tipo. Si no está cargado, la JVM buscará el archivo .class según el nombre de la clase y lo cargará. Una vez que un objeto de clase de cierto tipo se ha cargado en la memoria, se puede usar para generar todos los objetos de ese tipo.

Métodos importantes en clase

  • public Annotation [] getAnnotations () Obtiene todas las anotaciones en esta clase

  • getClassLoader () Obtiene el cargador de clases que cargó esta clase

  • getDeclaredMethods () Obtiene todos los métodos de esta clase

  • getReturnType () Obtiene el tipo de retorno del método

  • getParameterTypes () Obtiene los tipos de parámetros entrantes del método

  • isAnnotation () Prueba si esta clase es una clase de anotación

  • getDeclaredConstructors () Obtiene todos los constructores

  • getDeclaredMethod (String name, Class… parameterTypes) Obtiene el método de construcción especificado (parámetro: parámetro type.class)

  • getSuperclass () Obtiene la superclase de esta clase

  • getInterfaces () Obtiene todas las interfaces implementadas por esta clase

  • getFields () Obtiene todas las variables miembro modificadas públicamente en esta clase

  • getField (String name) Obtiene la variable miembro públicamente modificada del nombre especificado

  • newInstance () devuelve una nueva instancia de la clase representada por esta clase, creada llamando al constructor predeterminado (es decir, sin argumentos)

Casos de uso de reflexión

Clase de persona

public class Person {
private int age;
private String name;
public Person(){
 
}
public Person(int age, String name){
    this.age = age;
    this.name = name;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
}  

Clase SuperPerson

public class SuperPerson extends Person implements Smoke.Smoking{
private boolean isMan;
public void fly()
{
    System.out.println("走你~~");
}
public boolean isMan() {
    return isMan;
}
public void setMan(boolean iaMan) {
    isMan = iaMan;
}
@Override
public void smoke(int count) {
 
}
}

Clase de interfaz de humo

public class Smoke {
public interface Smoking {
    public void smoke(int count);
}
} 

Clase MainActivity

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Tests();
}
private void Tests() {
    try {
        //通过Java反射机制得到类的包名和类名
        Test1();
        System.out.println("===============================================");
        //验证所有的类都是Class类的实例对象
        Test2();
        System.out.println("===============================================");
        //通过Java反射机制,用Class 创建类对象[这也就是反射存在的意义所在],无参构造
        Test3();
        System.out.println("===============================================");
        //通过Java反射机制得到一个类的构造函数,并实现构造带参实例对象
        Test4();
        System.out.println("===============================================");
        //通过Java反射机制操作成员变量, set 和 get
        Test5();
        System.out.println("===============================================");
        //通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等
        Test6();
        System.out.println("===============================================");
        //通过Java反射机制调用类中方法
        Test7();
        System.out.println("===============================================");
        //通过Java反射机制获得类加载器
        Test8();
        System.out.println("===============================================");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Método Test1 ()

/**
* Demo1: 通过Java反射机制得到类的包名和类名
*/
public static void Test1() {
    Person person = new Person();
    System.out.println("Test1: 包名: " + person.getClass().getPackage().getName() + "," + "完整类名: " + person.getClass().getName());
}

Método Test2 ()

/**
* Demo2: 验证所有的类都是Class类的实例对象
*/
public static void Test2() throws ClassNotFoundException {
    //定义两个类型都未知的Class , 设置初值为null, 看看如何给它们赋值成Person类
    Class<?> class1 = null;
    Class<?> class2 = null;
 
    //写法1, 可能抛出 ClassNotFoundException [多用这个写法]
    class1 = Class.forName("com.tuba.yuanyc.audiomanagerdemo.Person");
    System.out.println("Test2:(写法1) 包名: " + class1.getPackage().getName() + "," + "完整类名: " + class1.getName());
 
    //写法2
    class2 = Person.class;
    System.out.println("Test2:(写法2) 包名: " + class2.getPackage().getName() + "," + "完整类名: " + class2.getName());
}

Método Test3 ()

/**
* Demo3: 通过Java反射机制,用Class 创建类对象[这也就是反射存在的意义所在]
*/
public static void Test3() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    Class<?> class1 = null;
    class1 = Class.forName("com.android.reflect.Person");
    //由于这里不能带参数,所以你要实例化的这个类Person,一定要有无参构造函数
    Person person = (Person) class1.newInstance();
    person.setAge(26);
    person.setName("kaiven");
    System.out.println("Test3: " + person.getName() + " : " + person.getAge());
}

Método Test4 ()

/**
* Demo4: 通过Java反射机制得到一个类的构造函数,并实现创建带参实例对象
*/
public static void Test4() throws ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
    Class<?> class1 = null;
    Person person1 = null;
    Person person2 = null;
    class1 = Class.forName("com.android.reflect.Person");
    //得到一系列构造函数集合
    Constructor<?>[] constructors = class1.getConstructors();
    try {
        person1 = (Person) constructors[0].newInstance();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    person1.setAge(28);
    person1.setName("zhuk");
    person2 = (Person) constructors[1].newInstance(29, "zhuk");
    System.out.println("Test4: " + person1.getName() + " : " + person1.getAge() + "  ,   " + person2.getName() + " : " + person2.getAge());
}

Método Test5 ()

/**
* Demo5: 通过Java反射机制操作成员变量, set 和 get
*/
public static void Test5() throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException, InstantiationException, ClassNotFoundException {
    Class<?> class1 = null;
    class1 = Class.forName("com.android.reflect.Person");
    Object obj = class1.newInstance();
    Field nameField = class1.getDeclaredField("name");
    nameField.setAccessible(true);
    nameField.set(obj, "cyy");
    System.out.println("Test5: 修改属性之后得到属性变量的值:" + nameField.get(obj));
}

Método Test6 ()

/**
* Demo6: 通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等
*/
public static void Test6() throws ClassNotFoundException {
    Class<?> class1 = null;
    class1 = Class.forName("com.android.reflect.Person");
    //取得父类名称
    Class<?> superClass = class1.getSuperclass();
    System.out.println("Test6:  SuperMan类的父类名: " + superClass.getName());
    System.out.println("===============================================");
    Field[] fields = class1.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        System.out.println("类中的成员: " + fields[i]);
    }
    System.out.println("===============================================");
    //取得类方法
    Method[] methods = class1.getDeclaredMethods();
    for (int i = 0; i < methods.length; i++) {
        System.out.println("Test6,取得SuperMan类的方法:");
        System.out.println("函数名:" + methods[i].getName());
        System.out.println("函数返回类型:" + methods[i].getReturnType());
        System.out.println("函数访问修饰符:" + Modifier.toString(methods[i].getModifiers()));
        System.out.println("函数代码写法: " + methods[i]);
    }
    System.out.println("===============================================");
    Class<?> interfaces[] = class1.getInterfaces();
    for (int i = 0; i < interfaces.length; i++) {
        System.out.println("实现的接口类名: " + interfaces[i].getName());
    }
}

Método Test7 ()

/**
* Demo7: 通过Java反射机制调用类方法
*/
public static void Test7() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
    Class<?> class1 = null;
    class1 = Class.forName("com.android.reflect.SuperPerson");
 
    System.out.println("Test7: \n调用无参方法fly():");
    Method method = class1.getMethod("fly");
    method.invoke(class1.newInstance());
 
    System.out.println("调用有参方法smoke(int m):");
    method = class1.getMethod("smoke", int.class);
    method.invoke(class1.newInstance(), 100);
}

Método Test8 ()

/**
* Demo8: 通过Java反射机制得到类加载器信息
* @throws ClassNotFoundException
*/
public static void Test8() throws ClassNotFoundException {
    Class<?> class1 = null;
    class1 = Class.forName("com.android.reflect.SuperPerson");
    String name = class1.getClassLoader().getClass().getName();
    System.out.println("Test8: 类加载器类名: " + name);
}
} 

resultado de la operación

01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test1: 包名: com.tuba.yuanyc.audiomanagerdemo,完整类名: com.tuba.yuanyc.audiomanagerdemo.Person
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test2:(写法1) 包名: com.android.reflect,完整类名: com.tuba.yuanyc.audiomanagerdemo.Person
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test2:(写法2) 包名: com.android.reflect,完整类名: com.tuba.yuanyc.audiomanagerdemo.Person
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test3: zhuk : 26
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test4: yyc : 28  ,   yyc : 29
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test5: 修改属性之后得到属性变量的值:cyy
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test6:  SuperMan类的父类名: java.lang.Object
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 类中的成员: private java.lang.String com.tuba.yuanyc.audiomanagerdemo.Person.name
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 类中的成员: private int com.android.reflect.Person.age
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test6,取得SuperMan类的方法:
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数名:getAge
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数返回类型:int
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数访问修饰符:public
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数代码写法: public int com.tuba.yuanyc.audiomanagerdemo.Person.getAge()
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test6,取得SuperMan类的方法:
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数名:getName
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数返回类型:class java.lang.String
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数访问修饰符:public
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数代码写法: public java.lang.String com.tuba.yuanyc.audiomanagerdemo.Person.getName()
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test6,取得SuperMan类的方法:
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数名:setAge
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数返回类型:void
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数访问修饰符:public
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数代码写法: public void com.tuba.yuanyc.audiomanagerdemo.Person.setAge(int)
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test6,取得SuperMan类的方法:
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数名:setName
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数返回类型:void
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数访问修饰符:public
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 函数代码写法: public void com.tuba.yuanyc.audiomanagerdemo.Person.setName(java.lang.String)
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test7:
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 调用无参方法fly():
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 走你~~
01-28 17:19:29.463  14972-14972/? I/System.out﹕ 调用有参方法smoke(int m):
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================
01-28 17:19:29.463  14972-14972/? I/System.out﹕ Test8: 类加载器类名: dalvik.system.PathClassLoader
01-28 17:19:29.463  14972-14972/? I/System.out﹕ ===============================================  

Modificación reflexiva de variables privadas

try {
  Student student = new Student("Han MeiMei");
  System.out.println("origin grade is " + student.getGrade());
 
  Class studentClass = Student.class;
  // 获取声明的 grade 字段,这里要注意 getField 和 getDeclaredField 的区别
  Field gradeField = studentClass.getDeclaredField("grade");
  
  // 如果是 private 或者 package 权限的,一定要赋予其访问权限
  gradeField.setAccessible(true);
  
  // 修改 student 对象中的 Grade 字段值
  gradeField.set(student, 2);
  System.out.println("after reflection grade is " + student.getGrade());
 
} catch (ReflectiveOperationException e) {
  e.printStackTrace();
}

Método privado de llamada reflexiva

try {
  Student student = new Student("Han MeiMei");
  
  // 获取私有方法,同样注意 getMethod 和 getDeclaredMethod 的区别
  Method goMethod = Student.class.getDeclaredMethod("goToSchool", null);
  // 赋予访问权限
  goMethod.setAccessible(true);
 
  // 调用 goToSchool 方法。
  goMethod.invoke(student, null);
 
} catch (ReflectiveOperationException e) {
  e.printStackTrace();
}

Los métodos de prueba anteriores cubren básicamente los métodos de reflexión habituales.

Resumen del uso de la reflexión

Al implementar funciones relacionadas a través de la reflexión, lo primero es leer detenidamente el código fuente, aclarar el contexto y luego encontrar los puntos de ruptura Estos puntos son generalmente métodos estáticos u objetos singleton y finalmente la implementación del código.

Supongo que te gusta

Origin blog.csdn.net/xfb1989/article/details/110875481
Recomendado
Clasificación