Java反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
反射的背景信息
servlet没有主方法(main) ,靠自己运行不起来,所以要引入 tomcat(Java写的带有java主方法的程序),依靠其运行,产生一系列关联性调用。
tomcat如何运行servlet?
正常:人眼可以清楚的看到类、对象、属性的名字,new一个类的对象,然后用类的对象调用。
tomcat : 不知道 servlet 的名称,不能new,只能用自己的工具,于是反射的作用出现了,用反射获取信息。
反射能获取到哪些信息呢? 凡是人眼能看到的都可以获取。
什么是java反射? 能够分析类信息的能力叫做反射。
为什么类信息存储在方法区当中?
.class文件叫做二进制字节码文件,首先进入方法区,实际上分为三个过程:
✔️ 硬盘阶段
class.forName("全类名")
✔️ class类对象阶段
进行封装,内部生成类对象(全局变量Field对象、构造器constructor、方法method)
类名.class
✔️ 运行时阶段
对象名.getClass
反射获取类信息的方式!!!
反射获取类信息的方式有 3 种:
-
通过对象的getClass方法进行获取
-
通过Class.forName()方法获取:调用静态方法 forName 获得类名对应的 Class 对象。
-
通过静态属性class可直接获取到该类型对应的Class对象 例如:T.class 将代表匹配的类对象
💡 tomcat 使用第二种方法,扫描所有目录,找到.class文件
非静态的方法必须依靠对象来执行,通过newInstance()获取类的对象
反射是否可以获得类的私有信息?
是可以的,把 .setAccessible() 方法设置成true
具体方法内容
1. 反射要想获取类信息,就必须生成类对象
2. 三种方式获取类对象:
◼️ 磁盘节点
Class class1 = Class.forName("com.qcby.Person");
◼️ 类对象阶段
Class class2 = Person.class;
◼️ 运行时阶段
Person person = new Person();
Class class3 = person.getClass();
3. 用三种阶段的对象获取类信息
Field[] fields1 = class1.getDeclaredFields();
for (Field field:fields1){
System.out.println(field);
}
Field[] fields2 = class2.getDeclaredFields();
for (Field field:fields2){
System.out.println(field);
}
Field[] fields3 = class3.getDeclaredFields();
for (Field field:fields3){
System.out.println(field);
}
获取全局变量信息的方式 Field
1. 类对象.getDeclaredFields()
获取所有的全局变量 需要使用Filed[]接收
2. 类对象.getFields()
获取所有的public修饰的全局变量 需要使用Filed[]接收
3. 类对象.getDeclaredField(“变量名”)
能够获取指定的任何修饰符修饰的全局变量信息 需要使用Filed接收
4. 类对象.getField(“变量名”)
能够获取指定的public修饰符修饰的全局变量信息 需要使用Filed接收
返回获取方法 Method
1. 类对象.getDeclaredMethods() :
这种方式获取所有的方法信息 Method[]
2. 类对象.getMethods() :
这种方式 获取public修饰的 方法信息 Method[]
3. 类对象.getDeclaredMethod("方法名",所有参数的类型)
获取所有的指定的方法信息 Method
4. 类对象.getMethod("方法名",所有参数的类型)
获取public的指定的方法信息 Method
返回获取构造器
1. 类对象.getDeclaredConstructors() :
这种方式获取所有的构造器信息 Constructor[]
2. 类对象.getConstructors() :
这种方式获取public修饰的构造器信息 Constructor[]
3. 类对象.getDeclaredConstructor("方法名",所有参数的类型)
获取所有的指定的构造器信息 Constructor
4. 类对象.getConstructor("方法名",所有参数的类型)
获取public的指定的构造器信息 Constructor
如何创建对象?
变量的赋值和取值操作
set() 和 get()
暴力反射,修改类中对象的姓名(私有属性),使用 getDeclaredFields() !!! 和 setAccessible(true)
一:只有变量时
public class Abc {
private String name;
@Override
public String toString() {
return "Abc{" +
"name='" + name + '\'' +
'}';
}
}
class TestAbc{
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Abc a = new Abc();
// 补全
// 把名字设置成张三
Class c1 = a.getClass();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);
name.set(a,"张三");
System.out.println(a.toString());
}
}
二:有构造方法时
如何执行方法? 使用 invoke()
public class Abc {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Abc{" +
"name='" + name + '\'' +
'}';
}
}
class TestAbc{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException {
Abc a = new Abc();
//补全
//把名字设置成张三
Class c1 = a.getClass();
Method method = c1.getDeclaredMethod("setName", String.class);
method.setAccessible(true);
method.invoke(a,"张三");
System.out.println(a.toString());
}
}