[Core Java] 04 Reflexión de Java

reflexión

Clase clase

Durante la ejecución del programa Java, la JVM mantendrá una (solo una) Classinstancia 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 Classinstancia única de esa clase .

Class getClass();

O use Classun método estático para obtener una Classinstancia a través de una cadena :

static Class forName(String className);

El último método es a través de classpalabras clave, por ejemplo:

Integer.class;
int.class;
// 基本类型也有 Class 实例

Además, Classexiste 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 Classdel 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 getNamemétodo para obtener el nombre.

String getName();

Modificador

También hay una getModifiersforma de obtener modificadores.

int getModifiers();

El int devuelto contiene el estado de si todos los modificadores se utilizan o no, que debe Modifierresolverse 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 getTypemétodo para obtener una Classinstancia del campo .

Class getType();

Lista de parámetros y excepción

Las clases Constructor y Method tienen métodos getParameterTypesy getExceptionTypespara 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 getReturnTypeclase 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, enumel valuesmé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 valuesla 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 $VALUESes 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 IllegalAccessExceptionexcepción.

Puede utilizar el setAccessiblemé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.

$VALUESDe hecho, es un dominio privado, que puede Modifierser 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 Constructormétodos estáticos newInstance:

Es diferente de Classla newInstanceque Constructorpermite a los constructores de parámetros no nulos a ser llamados.

Object newlnstance(Object[] args);

Ahora mira un ejemplo, el Arrays.copyOfmé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 Classel getComponentTypemétodo:

Class getComponentType();

La implementación es la siguiente:

Obtenga una Classinstancia del tipo de elemento mediante polimorfismo y luego llame para Array.newInstancecrear 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 invokemé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 nullcualquier valor (después de todo, no es necesario usarlo en un método estático this).

Este invokemétodo es similar al método de getsuma seten Fields . Para métodos con acceso restringido, también necesitamos llamar a la instancia de Método correspondiente para setAccessibleomitir 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.

Supongo que te gusta

Origin blog.csdn.net/qq_16181837/article/details/112295192
Recomendado
Clasificación