提示:以下是本篇文章正文内容,Java系列学习将会持续更新
一、基本概念
动态获取类信息以及动态调用该对象的属性和方法的功能称之为反射。
此处的动态
指的是运行时获取,javac编译 -> 生成.class文件 -> 运行主类
优点:
- 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。
- 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
- 反射是所有第三方框架的基础。
缺点:
- 使用反射会有效率问题,会导致程序效率降低。
- 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。
二、反射操作的核心类
实现反射操作需要4个核心类,这些类都在java.lang.reflect
包下
2-1 Class
1.在Java中获取一个类的class对象,有三种途径:
// Ⅰ.直接通过类名.class获取class对象
Class cls1 = Student.class;
// Ⅱ.通过该类的任意实例化对象,调用getClass()方法
Class cls2 = new Student().getClass();
// Ⅲ.使用Class类提供的静态方法 Class.forName(“包名.类名”);
Class cls3 = Class.forName("demo.Student");
2.调用 class对象 的newInstance()
方法产生 Student类 的实例
// 默认调用该类的无参构造,当访问不到无参构造时,无法使用该方法
Student stu = (Student) cls.newInstance();
2-2 Constructor
1.通过class 对象获取构造方法
① getConstructors()
只能获取当前类的 所有public
权限的构造方法
Constructor[] constructors = cls.getConstructors();
[public reflect.Student(java.lang.String,int,java.lang.String),
public reflect.Student()]
② getDeclaredConstructors()
能获取当前类的所有权限
的构造方法
Constructor[] constructors1 = cls.getDeclaredConstructors();
[public reflect.Student(java.lang.String,int,java.lang.String), reflect.Student(java.lang.String,int),
private reflect.Student(java.lang.String),
public reflect.Student()]
③ 拿到一个无参构造
的constructor对象
Constructor constructor = cls.getDeclaredConstructor();
④ 拿到一个有参构造
的constructor对象
Constructor constructor1 = cls.getDeclaredConstructor(String.class);
Constructor constructor2 = cls.getDeclaredConstructor(String.class, Integer.class);
Constructor constructor3 = cls.getDeclaredConstructor(String.class, Integer.class, String.class);
2.当拿到特定的Constructor对象时,就可以通过该对象来实例化Student对象
// 破坏封装,仅限当前JVM进程中的这个constructor1可用
constructor1.setAccessible(true);
Student stu = (Student) constructor1.newInstance();
2-3 Method
① 获取该类的所有方法Method对象,可以拿到当前类以及其父类的所有public权限
的方法
Method[] methods = cls.getMethods();
② 可以拿到当前类的所有权限
的方法,包括private权限
Method[] methods1 = cls.getDeclaredMethods();
③ 拿到当前类的某个方法
,getDeclaredMethod(方法名称,方法的参数类型)
Method staticMethod = cls.getDeclaredMethod("staticFunc", String.class);
2-4 Field
① 可以拿到当前类以及其父类的所有public的属性
Field[] fields = cls.getFields();
② 可以拿到当前类的所有权限的属性
,包括private权限
Field[] fields1 = cls.getDeclaredFields();
③ 可以拿到指定属性
Field field = cls.getDeclaredField("name");
三、反射的应用
3-1 通过反射调用方法
// 第一步,获取 class 对象
Class cls = new Demo().getClass();
// cls.getDeclaredMethod(方法名称,方法的参数类型)
Method staticMethod = cls.getDeclaredMethod("staticFunc", String.class);
// 静态方法的调用不需要实例化对象
// methodFunc.invoke(具体对象,方法参数);
staticMethod.invoke(null, "abcde");
Method methodFunc = cls.getDeclaredMethod("fun");
// fun()方法是private的,需要破坏封装
methodFunc.setAccessible(true);
// fun()是成员方法,必须通过Student的对象来调用
Student stu = (Student) cls.newInstance();
// 开始调用方法
// methodFunc.invoke(具体对象,方法参数);
methodFunc.invoke(stu);
通过反射来调用一个类的方法的过程:
- 先获取该类的class对象
- 通过getMethod或getDeclaredMethod获取这个方法的method反射对象
- 若该方法是一个成员方法,则需要产生该类的实例
- method.invoke(该类的实例, 方法的具体参数);
3-2 通过反射获取/修改属性
// 第一步,获取 class 对象
Class cls = Class.forname("demo.Student");
// 获取指定的属性
Field field = cls.getDeclaredField("name");
field.setAccessible(true); // 因为name是private修饰的属性
// name是成员属性,所以需要Student的实例化对象
Student stu = (Student) cls.newInstance();
// 设置属性值:set(具体对象, 属性值);
field.set(stu, "张三");
// 获取属性值:通过具体的Student对象获取name属性
System.out.println(field.get(stu));
通过反射来获取一个类的属性的过程:
- 先获取该类的class对象
- 通过getField或getDeclaredField获取指定属性的Field对象
- 创建该类的实例(若该属性是一个成员属性)
- set(obj-具体操作的对象, 要设置的属性值); get(obj-具体操作的对象);
总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是Java反射的学习,认识什么是反射,反射相关的类,以及反射的原理和过程。之后的学习内容将持续更新!!!