reflexión
Clase clase
Durante la ejecución del programa Java, la JVM mantendrá una (solo una) Class
instancia para cada clase , que se utiliza para describir la información de la clase.
Obtener Instancia
Cada clase hereda este método de la clase superior para devolver una Class
instancia única de esa clase .
Class getClass();
O use Class
un método estático para obtener una Class
instancia a través de una cadena :
static Class forName(String className);
El último método es a través de class
palabras clave, por ejemplo:
Integer.class;
int.class;
// 基本类型也有 Class 实例
Además, Class
existe un método para llamar a la construcción sin parámetros de esta clase para obtener una nueva instancia:
Object newlnstance();
Clases de campo, método y constructor
Obtenga sus ejemplos
Estas clases se utilizan para describir campos, métodos y constructores.
A través Class
del método en, devuelve la matriz correspondiente:
Field[] getFields();
// 返回该类及超类的公有域
Filed[] getDeclaredFie1ds();
// 返回该类的全部域
Method[] getMethods();
// 返回该类及超类的公有方法
Method[] getDeclareMethods();
// 返回该类及接口的全部方法
Constructor[] getConstructors();
// 返回全部公有构造器
Constructor[] getDeclaredConstructors();
// 返回所有构造器
O obtenga una instancia específica por descripción de cadena:
Field[] getField(String name);
Filed[] getDeclaredFie1d(String name);
// 通过域名获取 Field 实例
Method[] getMethod(String name, Class<?>... parameterTypes);
Method[] getDeclareMethod(String name, Class<?>... parameterTypes);
// 通过方法名及参数列表的 Class 实例获取 Method 实例
Constructor[] getConstructor(Class<?>... parameterTypes);
Constructor[] getDeclaredConstructor(Class<?>... parameterTypes);
// 通过参数列表的 Class 实例获取 Constructor 实例
nombre
Las clases Field, Method y Constructor tienen todas un getName
método para obtener el nombre.
String getName();
Modificador
También hay una getModifiers
forma de obtener modificadores.
int getModifiers();
El int devuelto contiene el estado de si todos los modificadores se utilizan o no, que debe Modifier
resolverse mediante métodos estáticos en la clase:
static String toString(int modifiers);
static boolean isAbstract(int modifiers);
static boolean isFinal (int modifiers);
static boolean islnterface(int modifiers);
static boolean isNative(int modifiers);
static boolean isPrivate(int modifiers);
static boolean isProtected(int modifiers);
static boolean isPubl(int modifiers);
static boolean isStat(int modifiers);
static boolean isStrict(int modifiers);
static boolean isSynchronized(int modifiers);
static boolean isVolatile(int modifiers);
Tipos de campos
En particular, Field tiene un getType
método para obtener una Class
instancia del campo .
Class getType();
Lista de parámetros y excepción
Las clases Constructor y Method tienen métodos getParameterTypes
y getExceptionTypes
para obtener el tipo de lista de parámetros y el tipo de excepción lanzada.
Class[] getParameterTypes();
Class[] getExceptionTypes();
Tipo de valor devuelto
El método tiene una getReturnType
clase para obtener el tipo de valor de retorno.
Class getReturnType();
Operación en tiempo de ejecución
Sabemos que las características de Java pueden ser características del compilador o características del intérprete.
Por ejemplo, enum
el values
método de la clase de enumeración devolverá una matriz de todas las instancias de enumeración, pero pocas personas piensan en dónde existe esta matriz, o qué magia terrible es. Sin embargo, este es en realidad el comportamiento del compilador.
Verificamos por reflexión.
Para clases de enumeración:
enum State {
Success, Fail;
}
Obtenemos la matriz de campos de esta clase e imprimimos sus nombres:
Arrays.asList(State.class.getDeclaredFields())
.forEach(item -> System.out.println(item.getName()));
Salida:
Éxito
Fallar
$ VALORES
Apareció un símbolo extraño $VALUES
, que en realidad es values
la matriz devuelta por el método.
Aquí hay algunos métodos terribles para operar dominios que de otra manera no podríamos operar:
Dominio de operación en tiempo de ejecución
Método de campo:
Object get(Object obj);
// 传入一个实例,返回该实例的域值
void set(Object obj ,Object newValue);
// 修改某个实例下该域的值
Antes de verificar $VALUES
, todavía tenemos un mecanismo de seguridad que discutir.
Si $VALUES
es un dominio privado, ¿no omitimos la verificación de acceso a la clase? Hasta ahora no, si ha intentado obtener el valor del dominio cuando lo ve aquí, se lanzará una IllegalAccessException
excepción.
Puede utilizar el setAccessible
método Field para establecer la bandera accesible:
void setAccessible(boolean flag);
// 为反射对象设置可访问标志,flag 为 true 表明屏蔽 Java 语言的访问检查,使得对象的私有属性也可以被 get 和 set
boolean isAccessible();
// 返回反射对象的可访问标志的值
static void setAccessible(AccessibleObject[] array, boolean flag);
// 批量为反射对象设置可访问标志
Los objetos de reflexión se refieren a clases como Campo, Método y Constructor.
Ahora, realmente hemos pasado por alto la verificación de acceso a clases.
$VALUES
De hecho, es un dominio privado, que puedeModifier
ser verificado por las clases mencionadas anteriormente :System.out.println(Modifier.isPrivate(State.class.getDeclaredField("$VALUES").getModifiers()));
Salida:
cierto
prueba:
Tenga en cuenta que estos dos métodos deben manejar excepciones.
try {
Field values = State.class.getDeclaredField("$VALUES");
values.setAccessible(true);
Arrays.asList((State[]) values.get(State.Success))
.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
}
Salida:
Éxito
Fallar
Construir objetos en tiempo de ejecución
Dado que Java prohíbe la conversión de tipos inseguros (downcasting), es difícil implementar un método universal.
El método universal significa que se puede utilizar para cualquier tipo. Por ejemplo, si un método acepta parámetros de Objeto, ¿qué debemos hacer si necesitamos construir una nueva instancia de este tipo?
Utilice Constructor
métodos estáticos newInstance
:
Es diferente de Class
la newInstance
que Constructor
permite a los constructores de parámetros no nulos a ser llamados.
Object newlnstance(Object[] args);
Ahora mira un ejemplo, el Arrays.copyOf
método de implementación :
Para crear una instancia de una matriz, puede utilizar un método estático de Array:
static Object newInstance(Class<?> componentType, int length);
// 通过数据类型和长度构造一个数组
El primer parámetro se obtiene mediante Class
el getComponentType
método:
Class getComponentType();
La implementación es la siguiente:
Obtenga una Class
instancia del tipo de elemento mediante polimorfismo y luego llame para Array.newInstance
crear una instancia de una matriz.
public static Object[] expend(Object[] arr, int length) {
Object[] newArr = (Object[]) Array.newInstance(arr.getClass().getComponentType(), length);
for (int i = 0; i < Math.min(arr.length, newArr.length); i++) {
newArr[i] = arr[i];
}
return newArr;
}
Puntero de método
El puntero de método se refiere a una instancia de la clase Method. Varios métodos para obtener instancias de Método, ya sea para obtener específicos o todos, se enumeran en detalle al principio de esta sección.
Método Cada instancia tiene un invoke
método, descrito para la llamada al método del objeto Método:
Object invoke(Object obj, Object... args)
El primer parámetro es el parámetro implícito del método, es decir this
, el objeto apuntado o entendido como el objeto que llama al método. Lo siguiente es la lista de parámetros del método.
Para los tipos estáticos, se puede pasar el primer parámetro o se puede pasar null
cualquier valor (después de todo, no es necesario usarlo en un método estático this
).
Este invoke
método es similar al método de get
suma set
en Fields . Para métodos con acceso restringido, también necesitamos llamar a la instancia de Método correspondiente para setAccessible
omitir la verificación de acceso.
Si no es necesario, no use punteros de función para llamar a métodos, lo cual es problemático y propenso a errores.
Si necesita una función de devolución de llamada, debe usar una interfaz o lambda.