基本概念
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.class, int.class);
if (Objects.nonNull(constructor)) {
System.out.println("constructor = " + constructor);
}
} catch (Exception e) {
}
// 11、获取指定参数的非public构造方法
try {
Constructor constructor1 = clazz.getDeclaredConstructor(int.class, String.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.class, TableName.class);
System.out.println("value = " + value.toString());
TableName annotation = AnnotationUtil.getAnnotation(BackupLog.class, TableName.class);
String value1 = annotation.value();
System.out.println("value1 = " + value1);
TableName annotation1 = AnnotationUtils.findAnnotation(BackupLog.class, TableName.class);
String value2 = annotation1.value();
System.out.println("value2 = " + value2);
}
}

原文始发于微信公众号(SimpleMemory):聊聊JAVA中的反射
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/137847.html