什么是反射
官方描述
Java反射机制是在运行状态中 对任意一个类 都能够知道这个类的属性和方法 对任意一个对象都能够调用它的任意一个方法和属性
这种动态获取的信息以及动态调用对象的方法得功能称为Java语言的反射机制
我的理解
强行窥探隐私 并对你洗脑 让你按照我的命令做事
反射的原理
(1)Java文件保存到本地硬盘 生成 .java 文件
(2)编译java文件生成 .class 文件
(3)使用Jvm将class文件通过类加载器加载到内存中
(4)class文件在内存中使用Class类表示
(5)通过反射获取Class类中的所有内容
反射的作用
说到反射的作用 其实在日常工作中很少用到 但优秀的框架 Spring SpringBoot 等等底层代码实现有60%左右用的都是反射 所以学习反射有助于我们对源代码的理解
类中的属性 方法 构造方法 与反射类的对应关系
类中的属性 ……在反射中使用Filed表示
类中的普通方法 ……在反射中使用method表示
类中的构造方法 ……在反射中使用 Constructor表示
上代码
首先创建一个Person类 我们反射就玩它
package com.it520.reflect.basic;
/**
* @author 玛丽莲梦明
* @描述 定义一个Person类 就玩这个类
*/
public class Person {
/**
* 姓名
*/
private String name;
/**
* id
*/
private String id;
/**
* 类中的静态方法
*/
public static void sayHello(String name) {
System.out.println(name + ":说了一句Hello");
}
/**
* 类中无参数的构造方法
*/
public Person() {
System.out.println("无参数构造方法");
}
/**
* 类中两个参数的构造方法 注意此构造方法是私有的
*/
private Person(String name, String id) {
System.out.println("有参数的构造方法");
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
/**
* 类中的普通方法
*/
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
使用反射操作无参数的构造方法
Class clazz = Class.forName("com.it520.reflect.basic.Person");
上面这种获取Class对象的方法是最常用的也是最好用的因为只要拿到类的全路径即可得到Class对象
当然也可以使用如下两种方式 但如果存在依赖关系会稍显麻烦 所以推荐使用 Class.forName() 本文使用 Class.forName()
Class clazz = new Person().getClass();
Class clazz = Person.clss
/**
* 使用反射操作构造方法
* <p>
* 操作无参数的构造方法
*/
@Test
public void TEST_01() throws Exception {
Class clazz = Class.forName("com.it520.reflect.basic.Person");
// 操作无参数的构造方法
Constructor constructor = clazz.getDeclaredConstructor();
// newInstance()方法得到对象的实例
Person person = (Person) constructor.newInstance();
person.setName("张三");
System.out.println(person.getName());
}
输出结果为 张三
操作有参数的构造方法
/**
* 使用反射操作构造方法
* <p>
* 操作有参数的构造方法
*/
@Test
public void TEST_02() throws Exception {
Class clazz = Class.forName("com.it520.reflect.basic.Person");
// 获取所有的构造方法
Constructor constructor = clazz.getDeclaredConstructor(String.class, String.class);
// 暴力破解 直接访问私有方法
constructor.setAccessible(true);
Person person = (Person) constructor.newInstance("张三", "110");
System.out.println(person.getName());
System.out.println(person.getId());
}
输出结果为 张三 110
使用反射操作属性
/**
* 使用反射操作属性
* <p>
* 操作私有属性 并赋值
*/
@Test
public void TEST_03() throws Exception {
Class clazz = Class.forName("com.it520.reflect.basic.Person");
// 得到一个对象的实例
Person person = (Person) clazz.getConstructor().newInstance();
/**
* 得到name属性
*/
Field name = clazz.getDeclaredField("name");
// 暴力破解 让我们可以直接访问私有方法
name.setAccessible(true);
/**
* 设置值, 相当于 person.setName("张三")
* 参数1 需要得到一个实例 这个实例就是类的实例 说白了就是Person类的实例
* 参数2 设置的值
*/
name.set(person, "张三");
// name.get(person) 相当于 p.getName()
System.out.println(name.get(person));
}
输出结果为 张三
使用反射操作普通方法
/**
* 使用反射操作普通方法
*/
@Test
public void TEST_04() throws Exception {
Class clazz = Class.forName("com.it520.reflect.basic.Person");
// 得到一个对象的实例
Person person = (Person) clazz.getConstructor().newInstance();
/**
* 参数一 为对象实例
* 参数二 获取的方法形参
*/
Method method = clazz.getDeclaredMethod("setName", String.class);
// 相当于执行了 setName()方法 并设置值
method.invoke(person, "队长");
System.out.println(person.getName());
}
输出结果为 队长
使用反射操作静态方法
/**
* 使用反射操作静态方法
* 当我们操作的是静态方法时 因为静态方法的调用方式是 类名.方法名 不需要类的实例
* 所以不需要类的实例 直接用null表示即可
*/
@Test
public void TEST_05() throws Exception {
Class clazz = Class.forName("com.it520.reflect.basic.Person");
// 通过反射获取到方法
Method sayHello = clazz.getMethod("sayHello", String.class);
// 静态方法无需传入类对象 直接给null即可
sayHello.invoke(null, "张三");
}
输出结果 张三:说了一句Hello
总结
以上足矣满足对反射的理解 毕竟实际开发中很少用到反射