聊聊JAVA中的反射

基本概念

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在Java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。Java反射机制主要提供了以下功能,这些功能都位于java.lang.reflect包。

在运行时判断任意一个对象所属的类。在运行时构造任意一个类的对象。在运行时判断任意一个类所具有的成员变量和方法。在运行时调用任意一个对象的方法。生成动态代理。要想知道一个类的属性和方法,必须先获取到该类的字节码文件对象。获取类的信息时,使用的就是Class类中的方法。所以先要获取到每一个字节码文件(.class)对应的Class类型的对象.

Java反射机制的优缺点

优点:

能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。与Java动态编译相结合,可以实现无比强大的功能。对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

缺点:

反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。

API详解

方法名 功能说明
Class -> static Class<?> forName(String className) 返回与具有给定字符串名称的类或接口关联的Class对象
Class(Constructor对象) -> T newInstance() 创建由此对象表示的类的新实例
Class -> String getName() 返回此对象表示的类的名称(类、接口、数组类、基元类型或 void)
Class -> Package getPackage() 获取此类的包
int getModifiers() 返回Java访问修饰符,该修饰符以整数编码
Class -> Method[] getMethods() 返回Method对象数组,其中包含反映此对象表示的类或接口的所有公共方法的对象,包括由类或接口声明的对象以及从超类和超级接口继承的对象
Class -> Method getMethod(String name,Class<?>…parameterTypers) 返回一个Method对象,该对象反映此对象表示的类或接口的指定公共成员方法
Class -> getDeclaredMethods() 获取类中所有的方法(public、protected、default、private)
Class -> getDeclaredMethod(String name,Class[] params) 获取类中(public、protected、default、private;不包括继承的方法)指定名称的方法,name参数指定方法的名字,parms参数指定方法的Class类型参数
Class -> Class<?>[] getInterfaces() 返回由此对象表示的类或接口实现的接口
Class -> Type getGenericSuperclass() 返回当前对象所表示的类的超类(包含该超类的泛型)
Class -> Class<? extends U> asSubclass(Class clazz) 强制转换此对象以表示由指定类对象表示的类的子类
Class -> T cast(Object obj) 将对象强制转换到此对象表示的类或接口
Class<? super T> getSuperclass() 返回表示由此表示的实体的超类(类、接口、基元类型或 void)
Class -> ClassLoader getClassLoader() 返回该类的类加载器
Class -> getFields() 获取类中public类型的属性(包括继承的public属性)
Class -> getField(String name) 获取类中的属性,name参数指定了属性的名称
Class -> getDeclaredFields() 获取类中所有属性(public、protected、default、private),但不包括继承的属性
Class -> getDeclaredField(String name) 获取类中的属性(public、protected、default、private),name参数指定了属性的名称
Class -> getConstructors() 获取类中的public构造方法
Class -> getConstructor(Class[] params) 获取类的特定构造方法,params参数指定构造方法的Class类型参数
Class -> getDeclaredConstructors() 获取类中所有的构造方法(public、protected、default、private)
Class -> getDeclaredConstructor(Class[] params) 获取类的特定构造方法(public、protected、default、private),params参数指定构造方法的参数类型
Field –>public void set(Object obj,Object value) 1.obj:要设置的字段所在的对象;2.value:要为字段设置的值
Field、Method –> setAccessible(true) 暴力反射,解除私有限定
Field –>public Object get(Object obj) obj:要获取的字段所在的对象
Method –> public Object invoke(Object obj,Object… args) obj : 要调用方法的对象(若方法为静态方法,则设置为null);args:调用方式时所传递的实参

代码演示

package com.asurplus.entity;

import lombok.Data;

/**
 * @author 公众号: SimpleMemory
 * @version 1.0.0
 * @ClassName BaseModel.java
 * @Description TODO
 * @createTime 2022年09月11日 11:02:00
 */

@Data
public class BaseModel {
    private String createDate;
    private String updateDate;
    private String createAt;
    private String updateAt;
}
package com.asurplus.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

/**
 * @author 公众号: SimpleMemory
 * @version 1.0.0
 * @ClassName BackupTask.java
 * @Description TODO
 * @createTime 2022年09月11日 11:02:00
 */

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("backup_task")
@ApiModel(value = "BackupTask对象", description = "备份任务信息")
public class BackupTask extends Model<BackupTask{

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "数据连接id")
    @TableField("db_id")
    private Integer dbId;

    @ApiModelProperty(value = "cron表达式")
    @TableField("cron")
    private String cron;

    @ApiModelProperty(value = "参数(JSON字符串)")
    @TableField("param")
    private String param;

    @ApiModelProperty(value = "状态(0-停止1-启动)")
    @TableField("status")
    private Boolean status;

    @ApiModelProperty(value = "库名")
    @TableField("database_name")
    private String databaseName;

    @ApiModelProperty(value = "表名")
    @TableField("tables_name")
    private String tablesName;

    @ApiModelProperty(value = "备注")
    @TableField("remark")
    private String remark;

    @ApiModelProperty(value = "创建时间")
    @TableField("create_time")
    private Date createTime;

    @ApiModelProperty(value = "删除状态(0--未删除1--已删除)")
    @TableField("del_flag")
    @TableLogic
    private Integer delFlag;

    @Override
    protected Serializable pkVal() {
        return this.id;
    }
}
package com.asurplus.task;

import cn.hutool.core.annotation.AnnotationUtil;
import com.asurplus.entity.BackupLog;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Objects;

/**
 * 反射的基本使用
 */

@Slf4j
public class Test {

    @SneakyThrows
    public static void main(String[] args) {
        // 1、获取Class对象的三种方案
        // (1)通过.class获取
        Class<BackupLog> aClass = BackupLog.class;
        // (2)通过Class.forName获取
        Class<?> clazz = Class.forName("com.asurplus.entity.BackupTask");
        // (3)通过实例对象的getClass()获取
        BackupLog backupLog = new BackupLog();
        Class<? extends BackupLog> backupLogClass = backupLog.getClass();

        // 2、获取全类名
        String name = aClass.getName();
        System.out.println("name = " + name); // name = com.asurplus.entity.BackupLog

        // 3、获取类名
        String simpleName = aClass.getSimpleName();
        System.out.println("simpleName = " + simpleName); // simpleName = BackupLog

        // 4、获取包名
        Package aPackage = aClass.getPackage();
        System.out.println("aPackage = " + aPackage); // aPackage = package com.asurplus.entity

        // 5、获取父类
        Class<? super BackupLog> superclass = aClass.getSuperclass();
        System.out.println("superclass = " + superclass); // superclass = class com.asurplus.entity.BaseModel

        // 6、获取当前实现的接口
        Class<?>[] interfaces = aClass.getInterfaces();
        for (Class c : interfaces) {
            System.out.println("c = " + c);
        }

        // 7、通过Class实例创建对象
        BackupLog backupLog1 = aClass.newInstance();
        System.out.println("backupLog1 = " + backupLog1);

        // 8、获取public构造方法
        Constructor<?>[] constructors = aClass.getConstructors();
        for (Constructor constructor : constructors) {
            String name1 = constructor.getName();
            System.out.println("name1 = " + name1);
        }

        // 9、获取所有构造方法
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {
            String name1 = constructor.getName();
            System.out.println("name1 = " + name1);
        }

        // 10、获取指定参数的public构造方法
        try {
            Constructor constructor = clazz.getConstructor(String.classint.class);
            if (Objects.nonNull(constructor)) {
                System.out.println("constructor = " + constructor);
            }
        } catch (Exception e) {
        }

        // 11、获取指定参数的非public构造方法
        try {
            Constructor constructor1 = clazz.getDeclaredConstructor(int.classString.class);
            if (Objects.nonNull(constructor1)) {
                System.out.println("constructor1 = " + constructor1);
            }
        } catch (Exception e) {
        }

        // 12、获取当前类和父类的public方法
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            String name1 = method.getName();
            System.out.println("name1 = " + name1);
        }

        // 13、获取当前类的所有方法
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            String name1 = method.getName();
            System.out.println("name = " + name1);
        }

        // 14、根据方法名和参数Class对象,获取当前类和父类的public方法
        try {
            Method method = aClass.getMethod("setMsgs", String.class);
            System.out.println("method = " + method);
        } catch (Exception e) {
        }

        // 15、根据方法名和参数Class对象,获取当前类的方法,无限制
        Method method = aClass.getDeclaredMethod("setMsgs", String.class);
        System.out.println("method = " + method);
        // 获取方法名
        String name2 = method.getName();
        // 获取返回值类型
        Class<?> returnType = method.getReturnType();
        String name1 = returnType.getName();
        System.out.println("name1 = " + name1);
        // 获取参数类型
        Class<?>[] parameterTypes = method.getParameterTypes();
        for (Class c : parameterTypes) {
            System.out.println("c = " + c);
        }
        // 获取修饰符
        int modifiers = method.getModifiers();
        System.out.println("modifiers = " + modifiers);

        // 16、调用方法
        BackupLog backupLog2 = aClass.newInstance();
        // 调用方法并获取返回值: 注意调用非public方法 报IllegalAccessException 异常;解决办法:设置 method.setAccessible(true);
        method.setAccessible(true);
        String aaa = (String) method.invoke(backupLog2, "aaa");
        System.out.println("aaa = " + aaa);

        // 17、调用静态方法
        Method method1 = aClass.getMethod("show", String.class);
        String ret = (String) method1.invoke(null"bbb");
        System.out.println("ret = " + ret);

        // 18、获取当前类和父类的public属性
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println("field.getName() = " + field.getName());
        }

        // 19、 获取当前类的所有属性
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println("field.getName() = " + field.getName());
        }

        // 20、 获取当前类和父类的public属性
        Field field = aClass.getField("content");
        System.out.println("field = " + field.getName());

        // 21、 获取当前类的属性,无限制
        Field field1 = aClass.getDeclaredField("content");
        System.out.println("field1 = " + field1.getName());

        // 22、 获取字段名 f.getName()
        Field[] declaredFields1 = aClass.getDeclaredFields();
        for (Field f : declaredFields1) {
            // 获取字段名
            System.out.println("field.getName() = " + f.getName());
            // 获取字段类型
            System.out.println("f.getType() = " + f.getType());
            // 获取字段修饰符
            int modifiers1 = f.getModifiers();
            System.out.println("modifiers1 = " + modifiers1);
            // 是否为private 修饰
            boolean aPrivate = Modifier.isPrivate(modifiers1);
            System.out.println("aPrivate = " + aPrivate);

        }

        // 23、 获取字段值
        BackupLog backupLog3 = new BackupLog();
        backupLog2.setMsg("123456");
        Field ff = aClass.getDeclaredField("msg");
        ff.setAccessible(true);  //非public设置true
        String msg = (String) ff.get(backupLog3);
        System.out.println("msg = " + msg);

        // 24、 设置字段值
        BackupLog backupLog4 = aClass.newInstance();
        Field fff = aClass.getDeclaredField("msg");
        fff.setAccessible(true); //非public设置true
        fff.set(backupLog3, "654321");
        System.out.println("backupLog4 = " + backupLog4);

        // 25、 获取类中注解中的值
        Object value = AnnotationUtil.getAnnotationValue(BackupLog.classTableName.class);
        System.out.println("value = " + value.toString());

        TableName annotation = AnnotationUtil.getAnnotation(BackupLog.classTableName.class);
        String value1 = annotation.value();
        System.out.println("value1 = " + value1);

        TableName annotation1 = AnnotationUtils.findAnnotation(BackupLog.classTableName.class);
        String value2 = annotation1.value();
        System.out.println("value2 = " + value2);
    }
}

聊聊JAVA中的反射

原文始发于微信公众号(SimpleMemory):聊聊JAVA中的反射

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/137847.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!