Reflexion
Reflection permite que un programa use ReflectionAPI para obtener información interna de cualquier clase durante la ejecución y manipular directamente las propiedades y métodos internos de cualquier objeto
Después de cargar la clase, se genera un objeto de tipo Clase en el área de método de la memoria de almacenamiento dinámico
¡Presta atención! Una clase solo puede tener una instancia correspondiente del tipo de clase
Este objeto encapsula la información estructural completa de la clase, puede ver la estructura de la clase a través de este objeto de clase
La diferencia entre lenguaje dinámico y lenguaje estático:
Lenguaje dinamico
El lenguaje de la estructura se puede cambiar en tiempo de ejecución, y se pueden agregar nuevas funciones, objetos y código en tiempo de ejecución
Las funciones existentes se pueden eliminar o modificar, y el código de tiempo de ejecución puede cambiar la estructura de acuerdo con ciertas condiciones
Lenguajes principales: Object-C, C #, JavaScript, PHP, Python, Eriang
Lenguaje estático
El lenguaje de programación que no puede cambiar el código en tiempo de ejecución es el lenguaje estático: Java, C, C ++
Aunque Java es un lenguaje estático, ¡el mecanismo de reflexión puede hacer que Java se vea dinámico! ! !
Funciones proporcionadas por el mecanismo de reflexión:
-Determinar la clase a la que pertenece el objeto
-Crear instancias de clases en tiempo de ejecución
-Determinar todas las variables miembro y métodos de una clase
-Obtener información genérica
-Llamadas miembros variables y métodos de cualquier instancia
- Manejar anotaciones en tiempo de ejecución
-Proxy dinámico! ! !
API
-java.lang.Class clase tipo clase
-java.lang.reflect.Method clase de método
-java.lang.reflect.Field clase de campo
-java.lang.reflect.Construtor clase constructora
Declaramos una clase personalizada
Persona de clase pública { nombre de cadena privada ; int int privado ; género booleano privado ; public Person () { } public Person (String name, int age, boolean gender) { this .name = name; this .age = age; este .gender = género; } public String getName () { return name; } public void setName (String name) { esto .name = nombre; } public int getAge () { return age; } public void setAge ( int age) { this .age = age; } public boolean isGender () { return gender; } public void setGender ( género booleano ) { this .gender = gender; } @Override public String toString () { return "Persona {" + "name = '" + name +' \ '' + ", age =" + age + ", gender =" + gender + '}' ; } }
A través de la reflexión para lograr acceso a las operaciones de clase e instancia
public class ReflectTest { @Test public void reflect () arroja la excepción { // El atributo de clase puede devolver el objeto de clase de esta clase Class <Person> personClass = Person. class ; // Obtener el objeto de la clase de constructor de esta clase, obtenido aquí Es un constructor de parámetros completo Constructor <Person> personClassConstructor = personClass.getConstructor (String. Class , int . Class , boolean . Class ); // Llame al constructor para crear un objeto Person Person person = personClassConstructor.newInstance ("杰哥", 28 , verdadero ); //Llamar a toString () del objeto Person; System.out.println (person.toString ()); // Mediante la reflexión, llame a la propiedad especificada por el objeto, método Field age = personClass.getDeclaredField ("age" ); // Desbloquear acceso Los permisos deben establecerse antes del acceso, de lo contrario no tiene sentido age.setAccessible ( true ); // A través de la instancia de campo de clase de la clase, llame al campo de edad de instancia de parámetro, modifique el valor // encontrado un error de excepción privado no se puede acceder // Clase cn.dai.Reflection .ReflectTest no puede acceder a un miembro de la clase cn.dai.Reflection.Person con modificadores "privados" age.set (persona, 10 ); System.out.println (persona); } }
Por ejemplo, métodos, constructores, estos son básicamente para obtener la clase de encapsulación correspondiente, obtener una instancia de la clase de encapsulación y luego llamar al método,
Si se trata de un derecho de acceso modificado de forma privada, configure la accesibilidad de la instancia encapsulada antes de usarla y luego ejecute la llamada
Proceso de carga de clase:
-Después de que el bytecode pasa por java.exe, se generarán uno o más archivos de bytecode de acuerdo con el contenido escrito por el código fuente
-java.exe interpretará y se ejecutará de acuerdo con un archivo de bytecode == bytecode se carga en la memoria
-Este paso anterior se llama carga de clase
-La clase cargada en la memoria, llamada clase de tiempo de ejecución, existe como una instancia de la clase Class
-Conversamente, el objeto de Class es una clase de bytecode que se ejecuta en la JVM
Cuatro formas de obtener instancias de clase:
public class GetClassStyle { @Test public void getClass4Way () lanza Exception { // first class.class Class <Person> personClass1 = Person. class ; System.out.println (personClass1); // instancia de la segunda clase.getClass ( ); la Persona Persona = nuevo nuevo la Persona (); la clase <? la extiende personClass2 la Persona => person.getClass (); System.out.println (personClass2); // tercer Class.forName nombre completo (la) clase clase < ?> personClass3 = Class.forName ("cn.dai.Reflection.Person"); System.out.println (personClass3); // Cuarta clase actual. Class.getClassLoader (). LoadClass (nombre completo de la clase "); Class <?> PersonClass4 = GetClassStyle. Class .getClassLoader (). LoadClass ("cn.dai.Reflection.Person" ); // Todas las instancias del método llamado son el mismo objeto } }
Use ClassLoader para cargar archivos de configuración
public class Loader { @Test public void loader () lanza Exception { Properties properties = new Properties (); // El objeto Stream solo puede leerse en el directorio del proyecto fuente actual. Si desea leer, la ruta debe escribirse como "src \" \ jdbc.properties " FileInputStream inputStream = new FileInputStream (" jdbc.properties " ); properties.load (inputStream); String driver = properties.getProperty (" driver " ); String url = properties.getProperty (" url " ); String username = properties.getProperty ("nombre de usuario" ); String password = properties.getProperty ("contraseña" ); System.out.println (controlador); System.out.println (url); System.out.println (nombre de usuario); System.out.println (contraseña); inputStream. close (); } @Test public void loader2 () lanza Exception { // Crear instancia de configuración Propiedades propiedades = nuevas Propiedades (); // La ubicación donde el cargador de clases lee el archivo por defecto es InputStream en el Módulo actual o paquete de proyecto src inputStream = Loader. class .getClassLoader (). getResourceAsStream ("jdbc.properties" ); // 加载 properties.load (flujoEntrada); // 读取 信息 String driver = properties.getProperty ("driver" ); String url = properties.getProperty ("url" ); String username = properties.getProperty ("nombre de usuario" ); Cadena contraseña = propiedades.getProperty ("contraseña" ); System.out.println (controlador); System.out.println (url); System.out.println (nombre de usuario); System.out.println (contraseña); inputStream.close (); } @Test public void loader3 () lanzaExcepción { // Crear una instancia de configuración Propiedades de propiedades = nuevas Propiedades (); // Codificación de URL de retorno% 20 La ubicación del cargador de clases para leer el archivo está por defecto en el Módulo actual o paquete src del proyecto Ruta de cadena = Cargador. Clase .getClassLoader () .getResource ("jdbc.properties" ) .getFile (); // Necesita decodificar String decode = URLDecoder.decode (ruta, "UTF-8" ); // Crear objeto de flujo InputStream inputStream = nuevo FileInputStream (decode); // Cargar configuración properties.load (inputStream); // Leer información String driver = properties.getProperty ("driver"); String url = properties.getProperty ("url" ); String username = properties.getProperty ("nombre de usuario" ); Cadena contraseña = propiedades.getProperty ("contraseña" ); System.out.println (controlador); System.out.println (url); System.out.println (nombre de usuario); System.out.println (contraseña); inputStream.close (); } }
Crear un objeto de la clase de tiempo de ejecución
@Test public void getInstanceByReflect () lanza Exception { Class <Person> personClass = Person. Class ; // Crea un objeto directamente desde la instancia de clase de la clase . No se recomienda usar este método en JDK9 + y posterior. // newInstance (); llamada interna El constructor de parámetros nulos en tiempo de ejecución, no hay construcción de parámetros nulos, la excepción de llamada // la clase de tiempo de ejecución debe proporcionar un constructor de parámetros nulos, los permisos de acceso no deben ser inferiores al predeterminado // javaBean requiere una razón de constructor de parámetros vacía: // a través de esto Reflexione para llamar al constructor para crear una instancia de Bean // Cuando la subclase hereda la clase de tiempo de ejecución, llame a super () para asegurarse de que la clase principal también tenga este constructor Person person = personClass.newInstance (); System.out.println (person); }
La naturaleza dinámica de la reflexión genera dinámicamente ejemplos.
@Test public void dynamic () arroja ClassNotFoundException, IllegalAccessException, InstantiationException { para ( int i = 0; i <100; i ++ ) { int random = new Random (). NextInt (3 ); Cadena classPath = nulo ; conmutador (aleatorio) { caso 0 : classPath = "java.util.Date" ; romper ; caso 1 : classPath = "java.lang.Object" ; romper ; caso 2 : classPath = "cn.dai.Reflection.Person" ; } Class <?> Name = Class.forName (classPath); Objeto instancia = nombre.nuevoInstance (); System.out.println (instancia); } }