当前位置:网站首页>反射
反射
2022-07-27 14:12:00 【James-Tom】
1、定义
百度百科:Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。
维基百科:反射指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。[1]用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
Java的反射机制的实现要借助于4个类:Class,Constructor,Field,Method;
2、应用场景
(1)、在Java类里面解析xml或properties里面的内容,载入类的Class实例。
这样就可以动态配置一些东西,不用每一次都要在代码里面去new或者做其他的事情,以后要改的话直接改配置文件,代码维护起来就很方便了。
(2)、在编码阶段不知道那个类名,要在运行期从配置文件读取类名, 这时候就没有办法硬编码new 一个实例,而必须用到反射才能创建这个对象.反射的目的就是为了扩展未知的应用。
比如你写了一个程序,这个程序定义了一些接口,只要实现了这些接口的jar都可以作为插件来插入到这个程序中。那么怎么实现呢?就可以通过反射来实现。就是把jar加载进内存,然后通过反射的方式来调用jar中的方法。
(3)、动态修改一些系统级别的API
比如某系统API类的某个属性设置了固定默认值,子类无法直接访问,而我们在自定义类的时候可能需要去修改这个默认值,就可以通过反射来实现。
…
3、常用API
1、获取反射中的class对象
private static void callApi1() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class clz = Class.forName("template.ClassA");//类所在包下的路径
Class clz2 = ClassA.class;
ClassA classA = new ClassA();
Class clz3 = classA.getClass();
System.out.println("类对象:" + clz);
System.out.println("类对象2:" + clz2);
System.out.println("类对象3:" + clz3);
}
2、通过反射创建类实例
private static void callApi2() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//方式1
Class clz = ClassA.class;
ClassA classA = (ClassA) clz.newInstance();
System.out.println("通过 Class 对象创建类实例:" + classA);
//方式2
Constructor constructor = clz.getConstructor();
ClassA classA2 = (ClassA) constructor.newInstance();
System.out.println("通过 Constructor 对象创建类实例:" + classA2);
//3、自定义构造函数的类实例
Constructor constructor2 = clz.getConstructor(String.class);
ClassA classA3 = (ClassA) constructor2.newInstance("Lily");
System.out.println("通过 Constructor 对象创建类有参构造函数实例:" + classA3);
}
通过 Constructor 对象创建类实例可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法(public)。
3、遍历方法和属性及调用
private static void callApi3() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//反射实例化
Class clz = Class.forName("template.ClassA");
Method[] methods = clz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("包含的方法:" + method);
}
Method[] publicMethods = clz.getMethods();
for (Method method : publicMethods) {
System.out.println("包含的公有方法:" + method);
}
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
System.out.println("包含的属性:" + field);
}
Field[] publicFields = clz.getFields();
for (Field field : publicFields) {
System.out.println("包含的公有属性:" + field);
}
Method setNameMethod = clz.getMethod("setName", String.class);
Constructor constructor = clz.getConstructor();
Object obj = constructor.newInstance();
setNameMethod.invoke(obj, "Tom.Hanks");
Method getNameMethod = clz.getMethod("getName");
System.out.println("反射实例化调用类的方法:" + getNameMethod.invoke(obj));
}
| 方法名称 | 描述 |
|---|---|
| getDeclaredMethods | 获取的是类自身声明的所有方法,包含public、protected和private方法 ;不能继承父类的方法 |
| getMethods | 获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。 |
| getDeclaredFields | 获取的是类自身声明的所有属性 ,包含public、protected和private属性;不能继承父类的属性 |
| getFields | 获取的是类的所有共有属性,这就包括自身的所有public属性,和从基类继承的、从接口实现的所有public属性。 |
4、案例
ClassA类:
package template;
/** * Created by Administrator on 2020/5/11. */
public class ClassA {
private String name;
private final String DEFAULT_NAME;//JVM 在编译阶段得到的 .class 文件已经将常量优化为具体的值,在运行阶段就直接使用具体的值了,所以即使修改了常量的值也已经毫无意义了。
public int TAG;
public ClassA() {
DEFAULT_NAME = "无";//将赋值放在构造函数中,构造函数是我们运行时 new 对象才会调用的,所以就不会直接为常量赋值。
}
public ClassA(String name) {
this.name = name;
this.DEFAULT_NAME = "无";//将赋值放在构造函数中,构造函数是我们运行时 new 对象才会调用的,所以就不会直接为常量赋值。
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String getDefaultName() {
return DEFAULT_NAME;
}
}
TestReflect类:
package template;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/** * Created by Administrator on 2020/5/11. */
public class TestReflect {
public static void main(String[] args) {
try {
callApi1();
callApi2();
callApi3();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
//1、获取反射中的class对象
private static void callApi1() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class clz = Class.forName("template.ClassA");
Class clz2 = ClassA.class;
ClassA classA = new ClassA();
Class clz3 = classA.getClass();
System.out.println("类对象:" + clz);
System.out.println("类对象2:" + clz2);
System.out.println("类对象3:" + clz3);
}
//2、通过反射创建类实例
private static void callApi2() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//方式1
Class clz = ClassA.class;
ClassA classA = (ClassA) clz.newInstance();
System.out.println("通过 Class 对象创建类实例:" + classA);
//方式2
Constructor constructor = clz.getConstructor();
ClassA classA2 = (ClassA) constructor.newInstance();
System.out.println("通过 Constructor 对象创建类实例:" + classA2);
//通过 Constructor 对象创建类实例可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法(public)。
Constructor constructor2 = clz.getConstructor(String.class);
ClassA classA3 = (ClassA) constructor2.newInstance("Lily");
System.out.println("通过 Constructor 对象创建类有参构造函数实例:" + classA3);
}
//3、遍历方法和属性及调用
private static void callApi3() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//反射实例化
Class clz = Class.forName("template.ClassA");
Method[] methods = clz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("包含的方法:" + method);
}
System.out.println("------------------------------分隔线------------------------------");
Method[] publicMethods = clz.getMethods();
for (Method method : publicMethods) {
System.out.println("包含的公有方法:" + method);
}
System.out.println("------------------------------分隔线------------------------------");
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
System.out.println("包含的属性:" + field);
}
System.out.println("------------------------------分隔线------------------------------");
Field[] publicFields = clz.getFields();
for (Field field : publicFields) {
System.out.println("包含的公有属性:" + field);
}
System.out.println("------------------------------分隔线------------------------------");
Method setNameMethod = clz.getMethod("setName", String.class);
Constructor constructor = clz.getConstructor();
Object obj = constructor.newInstance();
setNameMethod.invoke(obj, "Tom.Hanks");
Method getNameMethod = clz.getMethod("getName");
System.out.println("反射实例化调用:" + getNameMethod.invoke(obj));
}
}
输出:

5、总结
防止硬编码,更多的体现则是一种灵活性。
当在为私有属性赋值的时候需要设置setAccessible(true);
getDeclaredMethods:不能继承父类(或接口)的所有方法
getMethods:能继承父类(或接口)的公开方法
getDeclaredFields:不能继承父类(或接口)的所有属性
getFields:能继承父类(或接口)的公开属性
当子类想获取父类中的私有属性时,可以通过:getSuperclass的getDeclaredFields()方法来获取。
边栏推荐
- OBS 进阶之 DXGI 采集屏幕流程,并如何修改为自己的光标
- What you want most is the most comprehensive summary of C language knowledge. Don't hurry to learn
- Stm32f103c8t6 drives ssd1306 0.96 "IIC OLED display under Arduino frame
- LeetCode 81. 搜索旋转排序数组 II 二分/medium
- Win11壁纸变黑怎么办?Win11壁纸变黑了的解决方法
- 网络设备硬核技术内幕 路由器篇 16 DPDK及其前传(一)
- Shell programming specifications and variables
- LeetCode 240. 搜索二维矩阵 II medium
- Hdu3117 Fibonacci numbers [mathematics]
- [Yunxiang book club issue 13] multimedia processing tool ffmpeg tool set
猜你喜欢
随机推荐
The database uses PSQL and JDBC to connect remotely and disconnect automatically from time to time
网络设备硬核技术内幕 路由器篇 16 DPDK及其前传(一)
移动端使用vantUI的list组件,多个tab项来回切换时,列表加载多次导致数据无法正常展示
关于 CMS 垃圾回收器,你真的懂了吗?
How to help enterprises optimize office management
Timestamp of AAC, h264, etc
如何帮助企业优化Office管理
Graphical SQL is too vivid
FPGA时序约束分享04_output delay 约束
Construction and empirical research of post talent demand analysis framework based on recruitment advertisement
NEFU117 素数个数的位数【素数定理】
【WORK】关于技术架构
Win11壁纸变黑怎么办?Win11壁纸变黑了的解决方法
网络设备硬核技术内幕 路由器篇 15 从鹿由器到路由器 (下)
What is the execution method of the stand-alone parallel query of PostgreSQL?
Txt replace line breaks with spaces or cancel line breaks
图解 SQL,这也太形象了吧
Who can't capture packets these days? Wireshark packet capture and common protocol analysis are for you!
网络设备硬核技术内幕 路由器篇 13 从鹿由器到路由器(上)
炒黄金开户平台有没有正规,安全的








