Ordenar la comprensión del mecanismo de reflexión de Java

Inserte la descripción de la imagen aquí
En primer lugar, comprendamos la JVM, qué es la JVM, la máquina virtual Java, la razón por la cual Java puede multiplataforma es por esto, puede entenderlo como un proceso, programa, pero su función es ejecutar su código. La imagen de arriba es el modelo de memoria de Java. Nuestro enfoque está en un área de método, una pila y un montón. Cuando el maestro no profundiza cuando aprendo, solo le diré que la memoria de Java se divide en montón y pila. ¡Es fácil de entender!

Si escribió un fragmento de código: Object o = new Object ();

Se está ejecutando!

Primero, se iniciará la JVM, su código se compilará en un archivo .class, y luego el cargador de clases lo cargará en la memoria de la jvm, su Objeto de clase se cargará en el área de método y el objeto de clase de la clase de Objeto se creará en el montón. Este no es un objeto nuevo, sino un objeto de tipo de clase. Cada clase tiene solo un objeto de clase, que sirve como interfaz para la estructura de datos de la clase de área de método. Antes de crear un objeto, jvm primero verificará si la clase está cargada, buscará el objeto de clase correspondiente a la clase, si está cargado, luego asignará memoria para su objeto, la inicialización es el código: nuevo Object ().

El proceso anterior es que escriba el código que escribió en el jvm para ejecutarlo. Después de ejecutarlo, finalizará, el jvm se cerrará y su programa se detendrá.

¿Por qué hablar de esto? Porque para comprender la reflexión, debes saber en qué escena se usa.

El sujeto piensa que el objeto del programa anterior es nuevo, y el programa es equivalente a escribir en el jvm para ejecutarlo. Si una solicitud se encuentra repentinamente en un servidor, se necesita una clase, oops, pero no está cargada en el jvm, ¿quieres parar y escribir tu propio código, nuevo, oh, inicia el servidor, (cerebro)!

¿Qué es la reflexión? Cuando nuestro programa se está ejecutando, necesitamos cargar dinámicamente algunas clases. Es posible que estas clases no se usen antes, por lo que no necesitan cargarse en el jvm, sino que se cargan según sea necesario en tiempo de ejecución. Estos beneficios son evidentes para el servidor. Un ejemplo de la parte inferior de nuestro proyecto es a veces usar mysql, a veces usar oracle, necesita cargar dinámicamente la clase de controlador de acuerdo con la situación real, esta vez es útil la reflexión, suponiendo com.java.dbtest.myqlConnection, com.java.dbtest.oracleConnection Necesitamos usar esta clase. En este momento, nuestro programa se escribe de forma más dinámica, a través de la Clase tc = Class.forName ("com.java.dbtest.TestConnection"); a través del nombre completo de la clase, deje que JVM encuentre y Cargue esta clase, y si es Oracle, los parámetros entrantes se convierten en otro. En este momento puede ver los beneficios de la reflexión, ¡esta dinámica refleja las características de java! Para citar varios ejemplos, si ha contactado con spring, encontrará que cuando configura una variedad de beans, se configuran en forma de un archivo de configuración. Debe configurar qué beans necesita usar. Necesita cargar dinámicamente, su programa puede ejecutarse de manera robusta.

¿Qué es la reflexión?
Reflection (Reflection) es una de las características de Java, que permite ejecutar programas Java para obtener su propia información y puede manipular las propiedades internas de la clase u objeto.

La interpretación oficial de Oracle de la reflexión es:

Reflection permite que el código Java descubra información sobre los campos, métodos y constructores de clases cargadas, y utilice campos, métodos y constructores reflejados para operar en sus contrapartes subyacentes, dentro de las restricciones de seguridad.
La API acomoda aplicaciones que necesitan acceso a los miembros públicos de un objeto de destino (en función de su clase de tiempo de ejecución) o los miembros declarados por una clase determinada. También permite que los programas supriman el control de acceso reflexivo predeterminado.

El núcleo de la reflexión es que la JVM carga dinámicamente clases o llama a métodos / propiedades de acceso en tiempo de ejecución. No necesita saber de antemano (al escribir código o tiempo de compilación) quién es el objeto en ejecución.

La reflexión de Java proporciona principalmente las siguientes funciones:

Juzgue la clase a la que pertenece cualquier objeto
en tiempo de ejecución; construya el objeto de cualquier clase
en tiempo de ejecución; juzgue las variables miembro y los métodos de cualquier clase en tiempo de ejecución (incluso los métodos privados pueden llamarse mediante reflexión);
llame a cualquiera en tiempo de ejecución El enfoque del método de un objeto
: tiempo de ejecución en lugar de tiempo de compilación

En segundo lugar, el objetivo principal de la reflexión
Muchas personas piensan que la reflexión no se usa ampliamente en las aplicaciones de desarrollo de Java reales, pero no lo es. Cuando usamos un IDE (como Eclipse, IDEA), cuando ingresamos un objeto o clase y queremos llamar a sus propiedades o métodos, el compilador enumerará automáticamente sus propiedades o métodos cuando presione el punto. Utilizará la reflexión.

El uso más importante de la reflexión es desarrollar varios marcos generales. Muchos marcos (como Spring) son configurables (como configurar beans a través de archivos XML). Para garantizar la universalidad del marco, es posible que necesiten cargar diferentes objetos o clases y llamar a diferentes métodos de acuerdo con el archivo de configuración. Esta vez debe usar Para reflexionar, los objetos que deben cargarse se cargan dinámicamente en tiempo de ejecución.

Para dar un ejemplo, en el desarrollo utilizando el marco Struts 2, generalmente configuramos Action en struts.xml, como:

<action name="login"
class="org.ScZyhSoft.test.action.SimpleLoginAction"
method="execute">
<result>/shop/shop-index.jsp</result>
<result name="error">login.jsp</result>
</action>

El archivo de configuración establece una relación de mapeo con Action. Cuando la capa View envía una solicitud, StrutsPrepareAndExecuteFilter interceptará la solicitud y luego StrutsPrepareAndExecuteFilter creará dinámicamente una instancia de Action. Por ejemplo, si solicitamos login.action, StrutsPrepareAndExecuteFilter analizará el archivo struts.xml, recuperará la Acción cuyo nombre es login en la acción y creará una instancia SimpleLoginAction basada en el atributo de clase, y usará el método invoke para llamar al método de ejecución. Este proceso es inseparable de la reflexión.

Para los desarrolladores que trabajan con frameworks, la reflexión es pequeña pero muy útil, es el núcleo de varias implementaciones de contenedores. Para el desarrollador promedio, si no profundiza en el desarrollo del marco, utilizará un poco menos de reflexión, pero también es muy útil para comprender el mecanismo subyacente del marco para ayudar a enriquecer sus ideas de programación.

Tercero, la aplicación básica
de la reflexión. Mencionamos anteriormente que la reflexión puede usarse para determinar la clase a la que pertenece cualquier objeto, obtener un objeto de Clase, construir cualquier objeto y llamar a un objeto. Aquí presentamos el uso y la implementación de funciones básicas de reflexión (las clases relacionadas con la reflexión generalmente se encuentran en el paquete java.lang.relfect).

1.
Hay tres formas de obtener objetos de clase :

(1) Utilice el método estático forName de la clase Class:

public static Class<?> forName(String className)

Por ejemplo, en el desarrollo JDBC, este método a menudo se usa para cargar el controlador de la base de datos:

Class.forName(driver);

(2) Obtenga la clase de un objeto directamente, por ejemplo:

	
Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;

(3) Llame al método getClass () de un objeto, como:

	
StringBuilder str = new StringBuilder("123");
Class<?> klass = str.getClass();

2. Juzgue si es una instancia de una clase En
general, usamos la palabra clave instanceof para juzgar si es una instancia de una clase. Al mismo tiempo, también podemos usar el método isInstance () del objeto Class en reflexión para determinar si se trata de una instancia de una clase. Es un método nativo:

public native boolean isInstance(Object obj);

3. Crear instancias
Hay dos formas principales de generar objetos a través de la reflexión.

Use el método newInstance () del objeto Class para crear una instancia de la clase correspondiente al objeto Class.

Class<?> c = String.class;
Object str = c.newInstance();

Primero obtenga el objeto Constructor especificado a través del objeto Clase, y luego llame al método newInstance () del objeto Constructor para crear una instancia. Este método puede usar el constructor especificado para construir una instancia de la clase.

/获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("23333");
System.out.println(obj);

4. Obtención de métodos
La obtención de la colección de métodos de un objeto Class incluye principalmente los siguientes métodos:

El método getDeclaredMethods devuelve todos los métodos declarados por la clase o interfaz, incluidos los métodos público, protegido, predeterminado (paquete) y privado, pero no los métodos heredados.

public Method[] getDeclaredMethods() throws SecurityException

El método getMethods devuelve todos los métodos públicos de una clase, incluidos los métodos públicos de sus clases heredadas.

public Method[] getMethods() throws SecurityException

El método getMethod devuelve un método específico, donde el primer parámetro es el nombre del método, y los siguientes parámetros son los objetos del método correspondiente al objeto Class.

public Method getMethod(String name, Class<?>... parameterTypes)

Puede ser difícil entender lo que se describe de esta manera. Utilizamos ejemplos para comprender estos tres métodos:

package org.ScZyhSoft.common;
 
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
public class test1 {
public static void test() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> c = methodClass.class;
Object object = c.newInstance();
Method[] methods = c.getMethods();
Method[] declaredMethods = c.getDeclaredMethods();
//获取methodClass类的add方法
Method method = c.getMethod("add", int.class, int.class);
//getMethods()方法获取的所有方法
System.out.println("getMethods获取的方法:");
for(Method m:methods)
System.out.println(m);
//getDeclaredMethods()方法获取的所有方法
System.out.println("getDeclaredMethods获取的方法:");
for(Method m:declaredMethods)
System.out.println(m);
}
}
class methodClass {
 
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}

Los resultados de la ejecución del programa son los siguientes:

getMethods获取的方法:
public int org.ScZyhSoft.common.methodClass.add(int,int)
public int org.ScZyhSoft.common.methodClass.sub(int,int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
getDeclaredMethods获取的方法:
public int org.ScZyhSoft.common.methodClass.add(int,int)
public int org.ScZyhSoft.common.methodClass.sub(int,int)

Se puede ver que los métodos obtenidos a través de getMethods () pueden obtener los métodos de la clase padre, como los métodos definidos en java.lang.Object.
5. Obtención de información del constructor
El uso del constructor de la clase de obtención es similar al uso del método de obtención anterior. Principalmente a través del método getConstructor de la clase Class para obtener una instancia de la clase Constructor, y la clase Constructor tiene un método newInstance que puede crear una instancia de objeto:

public T newInstance(Object ... initargs)

Este método puede llamar al Constructor correspondiente para crear una instancia de objeto basada en los parámetros pasados.

6. Obtenga la información de las variables miembro (campos) de la clase.
Estos son principalmente estos métodos, que no se repetirán aquí:

getFiled: accede a las variables miembro públicas
getDeclaredField: todas las variables miembro declaradas, pero no puede obtener las variables miembro de sus clases principales
getFileds y getDeclaredFields. El método es el mismo que el anterior (consulte Método).

7. Llamar a un método
Cuando obtenemos un método de la clase, podemos usar el método invoke () para llamar a este método. El prototipo del método de invocación es:

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

Aquí hay un ejemplo:

public class test1 {
 
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> klass = methodClass.class;
//创建methodClass的实例
Object obj = klass.newInstance();
//获取methodClass类的add方法
Method method = klass.getMethod("add",int.class,int.class);
//调用method对应的方法 => add(1,4)
Object result = method.invoke(obj,1,4);
System.out.println(result);
}
 
}
 
class methodClass {
 
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}

Para una explicación detallada del método de invocación, escribiré un artículo más tarde para analizar el proceso de invocación en profundidad.
8. Uso de la reflexión para crear matrices Las
matrices son un tipo especial en Java, que puede asignarse a una Referencia de objeto. Echemos un vistazo a un ejemplo de uso de la reflexión para crear una matriz:

public static void testArray() throws ClassNotFoundException {
Class<?> cls = Class.forName("java.lang.String");
Object array = Array.newInstance(cls,25);
//往数组里添加内容
Array.set(array,0,"hello");
Array.set(array,1,"Java");
Array.set(array,2,"fuck");
Array.set(array,3,"Scala");
Array.set(array,4,"Clojure");
//获取某一项的内容
System.out.println(Array.get(array,3));
}

La clase Array es java.lang.reflect.Array. Creamos un objeto de matriz a través de Array.newInstance (), su prototipo es:

public static Object newInstance(Class<?> componentType, int length)
throws NegativeArraySizeException {
return newArray(componentType, length);
}

El método newArray es un método nativo y su implementación específica en HotSpot JVM se estudiará más adelante. Aquí, el código fuente se publica primero:

private static native Object newArray(Class<?> componentType, int length)
throws NegativeArraySizeException;

Directorio de origen: openjdk \ hotspot \ src \ share \ vm \ runtime \ reflection.cpp

arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) {
if (element_mirror == NULL) {
THROW_0(vmSymbols::java_lang_NullPointerException());
}
if (length < 0) {
THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
}
if (java_lang_Class::is_primitive(element_mirror)) {
Klass* tak = basic_type_mirror_to_arrayklass(element_mirror, CHECK_NULL);
return TypeArrayKlass::cast(tak)->allocate(length, THREAD);
} else {
Klass* k = java_lang_Class::as_Klass(element_mirror);
if (k->oop_is_array() && ArrayKlass::cast(k)->dimension() >= MAX_DIM) {
THROW_0(vmSymbols::java_lang_IllegalArgumentException());
}
return oopFactory::new_objArray(k, length, THREAD);
}
}

Además, los métodos set y get de la clase Array son métodos nativos, correspondientes a los métodos Reflection :: array_set y Reflection :: array_get en la JVM de HotSpot, que no se analizarán en detalle aquí.

** Cuatro consideraciones
para la reflexión ** Dado que la reflexión consumirá recursos adicionales del sistema, si no necesita crear dinámicamente un objeto, no necesita usar la reflexión.

Además, la verificación de permisos se puede ignorar cuando se llama al método por reflexión, por lo que puede romper la encapsulación y causar problemas de seguridad.

17 artículos originales publicados · Me gusta0 · Visitas 224

Supongo que te gusta

Origin blog.csdn.net/weixin_42531204/article/details/105328505
Recomendado
Clasificación