Resumo do aprendizado de Java: 39 (mecanismo de reflexão)

Mecanismo de reflexão

A reflexão em JAVA é um mecanismo de reflexão para obter informações dinamicamente e chamar métodos de objetos dinamicamente.
A reflexão Java está no estado de execução; para qualquer classe, você pode conhecer todas as propriedades e métodos dessa classe; para qualquer objeto, pode chamar qualquer um de seus métodos e propriedades e alterar suas propriedades. E essa também é uma natureza fundamental do Java como uma linguagem dinâmica. A função da reflexão Java é determinar a classe de qualquer objeto em tempo de execução, construir o objeto de qualquer classe em tempo de execução, determinar as variáveis ​​e métodos de membros de qualquer classe em tempo de execução e chamar o método de qualquer objeto em tempo de execução. Para gerar um proxy dinâmico. A reflexão é o recurso mais importante em Java. Quase todas as estruturas de desenvolvimento e tecnologias de aplicativos são baseadas na tecnologia de reflexão.

Reflexão epistêmica

Se você deseja obter informações sobre a classe deste objeto por meio de um objeto em um programa, pode usar o método getClass () (public public Class <?> GetClass ()) na classe Object.
Exemplo: Operação preliminar de reflexão

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

Instanciação de objeto de classe

Quando usamos o método getClass (), o tipo retornado é java.lang.Class, que é a classe de origem da operação de reflexão, ou seja, todas as operações de reflexão precisam iniciar a partir dessa classe, e o mais importante é que essa classe tenha as 3 instâncias a seguir Way 方法 way O caminho.

1. Chame o método getClass () na classe Object, mas você deve ter um objeto instanciado se desejar usar esse tipo de operação.

Esse método geralmente aparece na atribuição automática de classes Java simples e parâmetros de envio.O Struts e o Spring MVC fornecerão a conversão automática de parâmetros de formulário e classes Java simples.

Exemplo:

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. Use "class.class" para obter, neste momento você não precisa obter o objeto instanciado da classe especificada

Esse método geralmente é usado pelo usuário para definir o tipo de operação de reflexão, como armazenamento de dados no Hibernate e essas operações são usadas na consulta de ID.

Exemplo:

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. Chame o método fornecido pela classe Class: public static Class <?> ForName (String className) lança ClassNotFoundException.

Este método pode realizar a operação de reflexão do arquivo de configuração e da configuração de anotações.Quase todas as estruturas de desenvolvimento dependem desse método.

Exemplo:

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 reflexão

Dominando os três métodos de operação de instanciação de objetos Class, agora podemos usar a classe Class para controlar o reflexo da classe.

Métodos comuns da classe Class

Não. Método Tipo Descrição do produto
1 Classe estática pública <?> forName (String className) lança ClassNotFoundException Ordinário Instanciar o objeto Class pelo nome da classe definido pela string
2 Classe pública <?> [] getInterfaces () Ordinário Obtenha todas as interfaces implementadas pela classe
3 public String getName () Ordinário Obtenha o nome completo da classe de operação de reflexão
4 public String getSimpleName () Ordinário Obter nome da classe de operação de reflexão, excluindo o nome do pacote
5 Pacote público getPackage () Ordinário Obtenha o pacote em que a classe de operação de reflexão está localizada
6 Classe pública <? super T> getSuperclass () Ordinário Obter a classe pai da classe de operação de reflexão
7 public boolean isEnum () Ordinário Se a classe da operação de reflexão é uma enumeração
8 booleano público isInterface () Ordinário Se a classe da operação de reflexão é uma interface
9 booleano público isArray () Ordinário Se a classe da operação de reflexão é uma matriz
10 public T newInstance () lança InstantiationException, IllegalAccessException Ordinário Objeto instanciado de reflexão

Um dos métodos mais importantes na classe Class é o método newInstance (). Com esse método, você pode usar a reflexão para implementar a operação de instanciação de objeto do tipo de empacotamento do tipo Class, ou seja, também é possível instanciar o objeto sem usar a palavra-chave new.
Nota: Se você usar o método newInstance () para refletir o objeto instanciado, deverá fornecer um construtor sem parâmetros na classe, caso contrário, haverá um erro de sintaxe.

Exemplo: Use a reflexão para instanciar um 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

O tipo retornado pelo método newInstance () no programa acima é Object. Se necessário, você pode usar a operação de downcast do objeto para forçá-lo a se tornar uma instância de subclasse para operação.
Algumas pessoas podem perguntar qual é a vantagem de usar o método newInstance () para instanciar objetos.Não é perfumado usar novos diretamente?
De fato, como a palavra-chave new objeto instanciado precisa especificar explicitamente o método de construção de classe, new é o maior culpado que causa o acoplamento, portanto, o uso do método newInstance () para instanciar o objeto pode obter melhores operações de dissociação .

Chamar construção usando reflexão

Embora o método newInstance () na classe Class possa ser usado para implementar a operação do objeto de instanciação reflexiva, essa operação em si tem uma limitação de que o método de construção sem parâmetros deve ser fornecido na classe do objeto de operação.

Exemplo: Exemplo de Erro

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

Portanto, quando nenhum construtor sem parâmetros é fornecido na classe, a instanciação de reflexão do objeto deve ser implementada por meio da classe java.lang.reflect.Constructor . (java.lang.reflect é o pacote para todas as operações de reflexão)

Obtenha o construtor na classe

Não. Método Tipo Descrição do produto
1 public Constructor <?> [] getConstructors () lança SecurityException Ordinário Obtenha todos os métodos de construção
2 public Constructor <T> [] getConstructors (Class <?>… parameterTypes) lança NoSuchMethodException, SecurityException Ordinário Obter o método de construção do tipo de parâmetro especificado

Métodos de operação comuns da classe Constructor

Não. Método Tipo Descrição do produto
1 public class <?> [] getExceptionTypes () Ordinário Retornar todos os tipos que lançam exceções no construtor
2 public int getModifiers () Ordinário Obter o modificador do construtor
3 public String getName () Ordinário 取得构造方法的名字
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

Acho que você gosta

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