Resumen de aprendizaje de Java: 39 (mecanismo de reflexión)

Mecanismo de reflexión

La reflexión en JAVA es un mecanismo de reflexión para obtener información de forma dinámica y llamar dinámicamente métodos de objeto.
La reflexión de Java está en estado de ejecución, para cualquier clase, puede conocer todas las propiedades y métodos de esta clase; para cualquier objeto, puede llamar a cualquiera de sus métodos y propiedades, y puede cambiar sus propiedades. Y esta también es una naturaleza clave de Java como lenguaje dinámico. La función de la reflexión de Java es determinar la clase de cualquier objeto en tiempo de ejecución, construir el objeto de cualquier clase en tiempo de ejecución, determinar las variables miembro y los métodos de cualquier clase en tiempo de ejecución, y llamar al método de cualquier objeto en tiempo de ejecución. Para generar un proxy dinámico. La reflexión es la característica más importante en Java. Casi todos los marcos de desarrollo y tecnologías de aplicación se basan en la tecnología de reflexión.

Reflexión epistémica

Si desea obtener información sobre la clase de este objeto a través de un objeto en un programa, puede usar el método getClass () en la clase Object (public final Class <?> GetClass ())
Ejemplo: operación preliminar de reflexión

package Project.Study.Reflect;

import java.util.Date;

public class Test1 {
    public static void main(String[]args){
        Date date=new Date();				//产生实例化对象
        System.out.println(date.getClass());//直接反射输出对应类的信息
    }
}
//结果:
//class java.util.Date

Instanciación de objetos de clase

Cuando usamos el método getClass (), el tipo devuelto es java.lang.Class, que es la clase fuente de la operación de reflexión, es decir, todas las operaciones de reflexión deben comenzar desde esta clase, y lo más importante es que esta clase tiene las siguientes 3 instancias化 方法。 El camino.

1. Llame al método getClass () en la clase Object, pero debe tener un objeto instanciado si desea utilizar este tipo de operación.

Este método a menudo aparece en la asignación automática de clases Java simples y parámetros de envío. Struts y Spring MVC proporcionarán la conversión automática de parámetros de formulario y clases Java simples.

Ejemplo:

package Project.Study.Reflect;

import java.util.Date;

public class Test2 {
    public static void main(String[]args){
        Date date=new Date();               //产生实例化对象
        Class<?>cls=date.getClass();        //通过实例化对象取得Class对象
        //Class类中定义有“public String getName()”方法可以取得类的完整名称
        System.out.println(cls.getName());  //直接对象所在类的名称
    }
}
//结果:
//java.util.Date

2. Utilice "class.class" para obtener, en este momento no necesita obtener el objeto instanciado de la clase especificada

El usuario suele utilizar este método para establecer el tipo de operación de reflexión, como el almacenamiento de datos en Hibernate y dichas operaciones se utilizan en la consulta de ID.

Ejemplo:

package Project.Study.Reflect;

public class Test3 {
    public static void main(String[]args){
        Class<?>cls=java.util.Date.class;   //通过类名称取得Class类对象
        System.out.println(cls.getName());  //直接对象所在类的名称
    }
}
//结果:
//java.util.Date

3. Llame al método proporcionado por Class class: public static Class <?> ForName (String className) lanza ClassNotFoundException

Este método puede realizar la operación de reflexión del archivo de configuración y la configuración de Anotación. Casi todos los marcos de desarrollo se basan en este método.

Ejemplo:

package Project.Study.Reflect;

public class Test4 {
    public static void main(String[]args) throws Exception {
        //此处直接传递了一个要进行反射操作类的完整名称,是用字符串定义的
        Class<?>cls=Class.forName("java.util.Date");
        System.out.println(cls.getName());          //直接对象所在类的名称
    }
}
//结果:
//java.util.Date

Objeto instanciado de reflexión

Dominando los tres métodos de operación de instanciación de objetos Class, ahora podemos usar la clase Class para controlar el reflejo de la clase.

Métodos comunes de clase clase

No. Método Tipo Descripción
1 public static Class <?> forName (String className) arroja ClassNotFoundException Ordinario Instanciar el objeto de clase por el nombre de clase establecido por la cadena
2 public Class <?> [] getInterfaces () Ordinario Obtenga todas las interfaces implementadas por la clase
3 public String getName () Ordinario Obtenga el nombre completo de la clase de operación de reflexión
4 4 public String getSimpleName () Ordinario Obtener el nombre de la clase de operación de reflexión, excluyendo el nombre del paquete
5 5 Paquete público getPackage () Ordinario Obtenga el paquete donde se encuentra la clase de operación de reflexión
6 6 Clase pública <? super T> getSuperclass () Ordinario Obtenga la clase padre de la clase de operación de reflexión
7 7 public boolean isEnum () Ordinario Si la clase de la operación de reflexión es una enumeración
8 public boolean isInterface () Ordinario Si la clase de la operación de reflexión es una interfaz
9 9 public boolean isArray () Ordinario Si la clase de la operación de reflexión es una matriz
10 public T newInstance () lanza InstantiationException, IllegalAccessException Ordinario Objeto instanciado de reflexión

Uno de los métodos más importantes en la clase Class es el método newInstance (). Mediante este método, puede usar la reflexión para implementar la operación de creación de instancias de objeto del tipo de empaquetado de tipo Class.
Nota: Si usa el método newInstance () para reflejar el objeto instanciado, debe proporcionar un constructor sin parámetros en la clase, de lo contrario habrá un error de sintaxis.

Ejemplo: usar la reflexión para crear una instancia de un objeto

package Project.Study.Reflect;

class Book{
    public Book(){
        System.out.println("该类的无参方法");
    }
    @Override
    public String toString(){
        return "Hello World";
    }
}
public class Test5 {
    public static void main(String[]args) throws Exception {
        Class<?>cls=Class.forName("Project.Study.Reflect.Book");//设置要操作对象的类名称
        //反射实例化后的对象返回的结果都是Object类型
        Object object=cls.newInstance();                        //相当于使用new调用无参结构
        Book book=(Book)object;                                 //向下转型
        System.out.println(book);
    }
}
//结果:
//该类的无参方法
//Hello World

El tipo devuelto por el método newInstance () en el programa anterior es Object. Si es necesario, puede usar la operación downcast del objeto para forzarlo a convertirse en una instancia de subclase para la operación.
Algunas personas pueden preguntar cuál es la ventaja de usar el método newInstance () para crear instancias de objetos. ¿No es fragante usar new directamente?
De hecho, debido a que la palabra clave new instanciated object necesita especificar explícitamente el método de construcción de la clase, new es el mayor culpable que causa el acoplamiento, por lo que usar el método newInstance () para instanciar el objeto puede lograr mejores operaciones de desacoplamiento .

Llame a la construcción usando la reflexión

Aunque el método newInstance () en la clase Class se puede usar para implementar la operación de objeto de instancia reflexiva, dicha operación en sí misma tiene una limitación de que el método de construcción sin parámetros debe proporcionarse en la clase del objeto de operación.

Ejemplo: ejemplo de error

package Project.Study.Reflect;

class Book2{
    private String title;
    private double price;
    public Book2(String title,double price){
        this.price=price;
        this.title=title;
    }
    @Override
    public String toString(){
        return "图书名称:"+this.title+",价格:"+this.price;
    }
}
public class Test6 {
    public static void main(String[]args) throws Exception {
        Class<?>cls=Class.forName("Project.Study.Reflect.Book2");
        Object object=cls.newInstance();
        System.out.println(object);
    }
}
//结果:
//Exception in thread "main" java.lang.InstantiationException: Project.Study.Reflect.Book2
//	at java.base/java.lang.Class.newInstance(Class.java:585)
//	at Project.Study.Reflect.Test6.main(Test6.java:18)
//Caused by: java.lang.NoSuchMethodException: Project.Study.Reflect.Book2.<init>()
//	at java.base/java.lang.Class.getConstructor0(Class.java:3350)
//	at java.base/java.lang.Class.newInstance(Class.java:572)
//	... 1 more

Por lo tanto, cuando no se proporciona un constructor sin parámetros en la clase, la instancia de reflexión del objeto debe implementarse a través de la clase java.lang.reflect.Constructor . (java.lang.reflect es el paquete para todas las operaciones de reflexión)

Consigue el constructor en la clase

No. Método Tipo Descripción
1 public Constructor <?> [] getConstructors () lanza SecurityException Ordinario Obtén todos los métodos de construcción
2 public Constructor <T> [] getConstructors (Class <?> ... parameterTypes) lanza NoSuchMethodException, SecurityException Ordinario Obtenga el método de construcción del tipo de parámetro especificado

Métodos comunes de operación de la clase Constructor

No. Método Tipo Descripción
1 public Class <?> [] getExceptionTypes () Ordinario Devuelve todos los tipos lanzando excepciones en el constructor
2 public int getModifiers () Ordinario Obtener el modificador del constructor
3 public String getName () Ordinario 取得构造方法的名字
4 public int getParameterCount() 普通 取得构造方法中的参数个数
5 public Class <?>[] getParameterTypes() 普通 取得构造方法中的参数类型
6 public T newInstance(Object…initargs) throws InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException 普通 调用指定参数的构造实例化对象

注意:因为修饰符是用数字描述的,所有的修饰符都是一个数字,所以取得修饰符的方法返回的是int类型。

例:明确调用类中的有参构造

package Project.Study.Reflect;

import java.lang.reflect.Constructor;

class Book3{
    private String title;
    private double price;
    public Book3(String title,double price){
        this.title=title;
        this.price=price;
    }
    @Override
    public String toString(){
        return "图书名称:"+this.title+",价格:"+this.price;
    }
}
public class Test6 {
    public static void main(String[]args)throws Exception{
        Class<?>cls=Class.forName("Project.Study.Reflect.Book3");
        //明确地找到Book3类中两个参数的构造,第一个参数类型是String,第二个是double
        Constructor<?>constructor=cls.getConstructor(String.class,double.class);
        Object object=constructor.newInstance("Java",79.9);     //实例化对象
        System.out.println(object);
    }
}

//结果:
//图书名称:Java,价格:79.9

上程序的思路:
1.首先利用Class类对象取得此构造方法(返回Constructor类对象);
2.然后利用Constructor类中的newInstance()方法传递指定的数据,就可以调用有参构造进行对象的反射实例化。

反射调用方法

Class类取得普通方法的操作

No. 方法 类型 描述
1 public Method[] getMethods() throws SecurityException 普通 取得类中的全部方法
2 public Method[] getMethod(String name,Class<?>…parameterTypes) throws NoSuchMethodException,SecurityException 普通 取得类中指定方法名称与参数类型的方法

注:反射操作中,每一个方法都通过java.lang.reflect.Method类表示。

Method类的常用方法

No. 方法 类型 描述
1 public int getModifiers() 普通 取得方法的修饰符
2 public Class<?> getReturnType() 普通 取得方法的返回值类型
3 public int getParameterCount() 普通 取得方法中定义的参数数量
4 public Class<?> getParameterTypes() 普通 取得方法中定义的所有参数类型
5 public Object invoke(Object obj,Object…args) throws IllegalAccessException,IllegalArgumentException,InvocationTargetException 普通 反射调用方法并且传递执行方法所需要的参数数据
6 public Class<?> getExceptionTypes() 普通 取得方法抛出的异常类型

例:使用反射操作简单Java类的属性

package Project.Study.Reflect;

import java.lang.reflect.Method;

class Book4{
    private String title;
    public void setTitle(String title){
        this.title=title;
    }

    public String getTitle() {
        return title;
    }
}
public class Test7 {
    public static void main(String[]args)throws Exception{
        String fieldName="Title";
        Class<?>cls=Class.forName("Project.Study.Reflect.Book4");
        Object object=cls.newInstance();
        //取得类中的setTitle()方法
        Method setMet=cls.getMethod("set"+fieldName,String.class);
        //取得类中的getTitle()方法,本方法不接收参数并且没有返回值类型说明
        Method getMet=cls.getMethod("get"+fieldName);
        setMet.invoke(object,"Java书");      		//等价于Book4类对象.setTitle("Java书");
        System.out.println(getMet.invoke(object));  //等价于Book4类对象.getTitle();
    }
}
//结果:
//Java书

反射调用成员

Class类中取得成员的操作

No. 方法 类型 描述
1 public Field[] getDeclaredFields() throws SecurityException 普通 取得本类定义的全部成员
2 public Field[] getDeclaredFields(String name) throws NoSuchFieldException,SecurityException 普通 取得本类指定名称的成员
3 public Field[] getFields() throws SecurityException 普通 取得本类继承父类的全部成员
4 public Field[] getField(String name) throws NoSuchFieldException,SecurityException 普通 取得本类继承父类中指定名称的成员

Field类的常用方法

No. 方法 类型 描述
1 public Class<?> getType() 普通 取得改成员的类型
2 public Object get(Object obj) throws IllegalAccessException,IllegalArgumentException 普通 取得指定对象中的成员的内容,相当于直接调用成员
3 public void set(Object obj,Object value) throws IllegalAccessException,IllegalArgumentException 普通 设置指定对象中的成员内容,相当于直接利用对象调用成员设置内容

注意:不管使用反射调用的是普通方法还是调用类中的成员,都必须存在实例化对象(可以依靠反射取得实例化对象),因为类中的属性必须在类产生实例化对象后才可以使用。

例:利用反射直接操作私有成员

package Project.Study.Reflect;

import java.lang.reflect.Field;

class Book5{
    private String title;
}
public class Test8 {
    public static void main(String[]args)throws Exception{
        Class<?>cls=Class.forName("Project.Study.Reflect.Book5");   //取得反射对象
        Object object=cls.newInstance();                            //必须给出实例化对象
        Field titleField=cls.getDeclaredField("title");     //取得类中的title属性
        titleField.setAccessible(true);                             //取消封装,使title属性可以被外界访问
        titleField.set(object,"Java书");                            //相当于:Book5类对象.title="数据"
        System.out.println(titleField.get(object));                 //相当于:Book5类对象.title
    }
}
//结果:
//Java书
发布了49 篇原创文章 · 获赞 25 · 访问量 1504

Supongo que te gusta

Origin blog.csdn.net/weixin_45784666/article/details/105386852
Recomendado
Clasificación