[notas de Java] mecanismo de reflexión

Visión de conjunto:

Lenguaje dinámico:

Una clase de lenguajes cuya estructura se puede cambiar en tiempo de ejecución. Por ejemplo, se pueden introducir nuevas funciones, objetos y código; se pueden eliminar funciones existentes u otros cambios estructurales.

Lenguaje estático:

Un lenguaje cuya estructura de tiempo de ejecución es inmutable es un lenguaje estático.

Java no es un lenguaje dinámico, pero se puede decir que es un lenguaje cuasi-dinámico, es decir, Java tiene una cierta naturaleza dinámica, y el mecanismo de reflexión se puede utilizar para obtener características similares a los lenguajes dinámicos.


Mecanismo de reflexión: Java Reflection. Permite que el programa obtenga la información interna de cualquier clase por medio de la API de Reflection durante la ejecución, y puede manipular directamente los métodos de propiedad interna de cualquier objeto

Después de cargar la clase, se genera un objeto de tipo Class en el área de métodos de la memoria del montón (una clase tiene solo un objeto Class), y este objeto contiene la información estructural completa de la clase. Podemos ver la estructura de la clase a través de este objeto. Este objeto es como un espejo, a través del cual se puede ver la estructura de la clase, por lo que la imagen se llama reflejo.

Ventajas de la reflexión:

Puede lograr la creación y compilación de objetos dinámicos, flexible

Desventajas de la reflexión:

Afecta el rendimiento.


API relacionada con la reflexión:

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Construtor:代表类的构造器

 

 

  Una clase tiene solo un objeto de clase en la memoria

Después de cargar una clase, toda la estructura de la clase se encapsula en el objeto Clase

 clase clase:

El método Class getclass() está definido en la clase Object, y este método será heredado por todas las subclases

Para cada clase, JRE reserva un objeto de tipo de clase invariable para ella, y un objeto de tipo de clase contiene una estructura específica

●La clase en sí también es una clase

●Los objetos de clase solo pueden ser creados por el sistema

● Una carga solo tendrá una instancia de Clase en la JVM.

Un objeto Class corresponde a un archivo .class cargado en la JVM

Cada instancia de una clase recordará a partir de qué instancia de clase se generó

●A través de Class, todas las estructuras cargadas de una clase se pueden obtener por completo

La clase Class es la raíz de Reflection. Para cualquier clase que desee cargar y ejecutar dinámicamente, primero debe obtener el objeto Class correspondiente.

Obtenga una instancia de la clase Class:

Si se conoce la clase específica, se puede obtener a través del atributo de clase de la clase, que tiene alta seguridad y confiabilidad.

Class c=Person.class;

Si se conoce una instancia de una clase, llame al método getClass() de la instancia para obtener el objeto Class

Class c=person.getClass();

Se conoce el nombre de clase completo de una clase, y la clase está en el classpath, que se puede obtener a través del método estático forName() de la clase Class, que puede generar una ClassNotFoundException

Class c=Class.forName("路径/类名")

 

        Person person=new Student();
        //通过对象获得
        Class c1=person.getClass();
        //通过forname获得
        Class c2=Class.forName("Reflection.Student");
        //通过类名.class获得
        Class c3=Student.class;
   ------------------------------------------------------

        //基本内置类型的包装类都有一个TYPE属性
        Class c4=Integer.TYPE;
        System.out.println(c4.hashCode());
        //获得父类类型Person
        Class c5=c1.getSuperclass();

¿Qué tipos pueden tener objetos Class?

clase: clase externa, clase interna miembro, clase interna estática, clase interna local, clase interna anónima

interfaz: interfaz

[]: matriz

enumeración: enumeración 

anotación: anotación

tipo primitivo: tipo de datos básico

vacío

Siempre que el tipo de elemento sea el mismo que la dimensión, es una clase 

Análisis de memoria JAVA:

La carga de clases y la comprensión de ClassLoader:

carga:

Cargue el contenido del código de bytes del archivo de clase en la memoria y convierta estos datos estáticos en estructuras de datos de tiempo de ejecución en el área de método

Luego genere un objeto java.lang.Class que represente esta clase

Enlace:

El proceso de incorporar el código binario de una clase Java en el estado de ejecución de la JVM

Validación: asegúrese de que las clases cargadas se ajusten a la especificación JVM y no tengan problemas de seguridad

Preparación: la etapa de asignación formal de memoria para el recorrido de clases (estático) y la configuración del valor inicial predeterminado de las variables de clase, que se asignarán en el área de método

Resolución: el proceso de reemplazar la referencia simbólica (nombre constante) del grupo de constantes de la máquina virtual con una referencia directa (dirección)

inicialización:

El proceso de ejecutar el método constructor de clase <clinit>(). El método del constructor de clase <clinit>() se genera mediante la recopilación automática de asignaciones de todas las variables de clase en la clase en tiempo de compilación y combinando las declaraciones en el bloque de código estático. (El constructor de clase es para construir información de clase, no el constructor para construir objetos de esta clase)

Al inicializar una clase, si encuentra que su clase principal no se ha inicializado, primero debe activar la inicialización de su clase principal

La máquina virtual garantiza que un método de clase <clinit>() esté correctamente bloqueado y sincronizado en un entorno de subprocesos múltiples.

   Referencia activa de la clase (debe ocurrir la inicialización de la clase)
➢ Cuando se inicia la máquina virtual, inicialice la clase donde se encuentra el método principal ➢
Nuevo objeto de una clase
➢ Llamar a miembros estáticos (excepto las constantes finales) y métodos estáticos de la clase
➢ Usar java .lang El método del paquete .reflect realiza una llamada de reflexión a la clase
➢ Cuando se inicializa una clase, si su clase principal no se ha inicializado,
   la referencia pasiva de su clase principal se inicializará primero (la inicialización de la clase no ocurrirá)
➢ Al acceder a un dominio estático, solo se inicializará la clase que realmente declara el campo. Por ejemplo: cuando se hace referencia a la variable estática de la clase principal a través de una subclase, no provocará la inicialización de la subclase.
➢ Definir una referencia de clase a través de una matriz no activará la inicialización de
esta clase. clase de llamada)

cargador de clases:

➢El papel de la carga de clases: cargue el contenido del código de bytes del archivo de clase en la memoria, convierta estos datos estáticos en la
estructura de datos de tiempo de ejecución del área de métodos y luego genere un objeto java.lang.Class que represente esta clase en el montón , como la
entrada de acceso para datos de clase en el área de método .
➢ Caché de clases: el cargador de clases JavaSE estándar puede buscar clases a pedido, pero una vez que una clase se carga en el cargador de clases,
permanecerá cargada (almacenada en caché) durante un período de tiempo. Sin embargo, el mecanismo de recolección de elementos no utilizados de JVM puede reciclar estos objetos de clase.
 

Obtener información de la clase:

        Class c1=Class.forName("Reflection.User");
        //获得类的名字
        System.out.println(c1.getName());//获得包名+类名
        System.out.println(c1.getSimpleName());//获得类名
        //获得类的属性
        Field[]field11=c1.getFields();//获取Public属性
        Field[]fields=c1.getDeclaredFields();//获取全部属性
        //获取指定属性的值
        Field name=c1.getDeclaredField("name");
        //获得类的方法
        Method[]methods=c1.getMethods();//获得本类及其父类的全部Public方法
        methods=c1.getDeclaredMethods();
        //获取类的指定方法
        //需要传入参数类型
        Method getName=c1.getMethod("getName",null);
        Method setName=c1.getMethod("setName",String.class);
        //获取构造器
        Constructor[] constructors = c1.getConstructors();
        constructors=c1.getDeclaredConstructors();
        //获取指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class,int.class,int.class);

Crear objetos dinámicamente a través de la reflexión.

       //通过构造器创建对象
        Class c1=Class.forName("Reflection.User");
        //获取构造器后newInstance
        User user=(User) 
      c1.getDeclaredConstructor(String.class,int.class,int.class).newInstance("李",001,18);
        System.out.println(user);
        //通过反射调用方法:invoke
        c1.getDeclaredMethod("setName", String.class).invoke(user,"asd");
        //invoke:激活  (对象,方法的参数值)

        //通过反射操作属性

      Field name=c1.getDeclaredField("name");
      name.setAccessible(true);//设置私有成员的值时需要设置为true,否则访问不了

         name.set(user,"lll");

Si el método o campo se declara como privado, debe llamar explícitamente al método setAccessible(true) antes de llamar al método para que el método privado sea accesible.

setAccessible: cambie para habilitar y deshabilitar los controles de seguridad de acceso

Los objetos Method, Field, Constructor usan el método setAccssible()

El valor del parámetro es verdadero, lo que indica que el objeto reflejado debe cancelar la verificación de acceso al idioma Java cuando se usa.

*Si se debe usar la reflexión en el código, y el código debe llamarse con frecuencia, establezca en verdadero

* También se puede acceder a miembros privados que de otro modo serían inaccesibles

Un valor de parámetro de falso indica que el objeto reflejado debe implementar la verificación de acceso al lenguaje Java

Análisis de rendimiento:

 Reflexión para obtener anotaciones

        Class aClass = Class.forName("Reflection.Student1");
        //通过反射获得注解
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);//@Reflection.Table("db_stu")
        }
        Table table=(Table)aClass.getAnnotation(Table.class);
        System.out.println(table.value());//db_stu

        //获得类指定的注解
        Field f=aClass.getDeclaredField("name");
        FieldTable annotation = f.getAnnotation(FieldTable.class);
        System.out.println(annotation);//@Reflection.FieldTable(colName="db_name", type="varchar", length=3)
        System.out.println(annotation.colName());// db_name
        System.out.println(annotation.type());//varchar
        System.out.println(annotation.length());//3

    }
}
@Table("db_stu")
class Student1{
    @FieldTable(colName = "db_id",type = "int",length =10)
    private int id;
    @FieldTable(colName = "db_age",type="int",length = 10)
    private int age;
    @FieldTable(colName = "db_name",type="varchar",length = 3)
    private String name;

    public Student1() {
    }

    public Student1(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldTable{
    String colName();
    String type();
    int length();
}

Supongo que te gusta

Origin blog.csdn.net/m0_52043808/article/details/124076887
Recomendado
Clasificación