1.反射
1.1反射概述
1.java反射机制是在运行状态时,对于任意一个类,都可以知道这个类的所有属性和方法;
动态获取信息以及动态调用对象的方法称为java反射机制;
2.反射的三种方式
(1)Object类的getClass()方法,判断两个对象是否是同一个字节码文件;
(2)静态属性class,锁对象;
(3)Class类中静态方法forName(),读取配置文件;
public class demo2_Ref {
/**
* @param args
* 反射的三种获取方式
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException {
Class clazz1 = Class.forName("day8.Fac_Method.Person");//1
Class clazz2 = Person.class;//2
Person p = new Person();
Class clazz3 = p.getClass();//3
System.out.println(clazz1==clazz2);
System.out.println(clazz2==clazz3);
}
}
1.2反射之Class.forName()读取配置文件
—newInstance为class创建一个实例对象
//反射实现
BufferedReader br = new BufferedReader(new FileReader("config.properties"));
Class clazz = Class.forName(br.readLine());
Fruit f = (Fruit) clazz.newInstance();//为class创建一个实例对象
代码实现:
第一步:创建配置文件config.properties;
day8.Fac_Method.Apple
第二步:
package day8.Fac_Method;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class demo3 {
public static void main(String[] args) throws Exception{
//反射实现
BufferedReader br = new BufferedReader(new FileReader("config.properties"));
Class clazz = Class.forName(br.readLine());
Fruit f = (Fruit) clazz.newInstance();
Juicer j = new Juicer();
j.run(f);
}
}
interface Fruit{
public void squeeze();
}
class Apple implements Fruit{
public void squeeze(){//榨汁方法
System.out.println("榨苹果汁");
}
}
class Orange implements Fruit{
public void squeeze(){
System.out.println("榨橘子汁");
}
}
//榨汁机
class Juicer{
public void run(Fruit f){//榨汁机运行方法
f.squeeze();
}
}
1.3通过反射获取构造方法
无参构造与有参构造获取对象的方法
1.获取字节码文件
Class clazz = Class.forName("day8.Fac_Method.Person");
2.获取有参构造
Constructor c = clazz.getConstructor(String.class,int.class);
3.通过有参构造创建对象
Person p = (Person) c.newInstance("张三",23);
4.打印输出p;
Person [name=张三, age=23]
5.代码实现:
第一步:创建Person类
public class Person {
private String name;
private int age;
/*public Person() {
super();//注释掉无参,在反射中就只能通过有参来实现
}*/
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
第二步:通过反射获取对象(无参与有参)
/**
* @author ZHENG
* 通过反射获取无参构造和获取有参构造的区别
*/
public class demo4_Constrct {
public static void main(String[] args) throws Exception {
//1.获取字节码文件
Class clazz = Class.forName("day8.Fac_Method.Person");
/*
//2.通过无参构造获取对象
Person p = (Person) clazz.newInstance();
System.out.println(p);
*/
//2.获取有参构造
Constructor c = clazz.getConstructor(String.class,int.class);
//通过有参构造创建对象
Person p = (Person) c.newInstance("张三",23);
System.out.println(p);
}
}
1.4通过反射获取成员变量
1.获取字节码文件
Class clazz = Class.forName("day8.Fac_Method.Person");
2.获取有参构造
Constructor c = clazz.getConstructor(String.class,int.class);
3.通过有参构造创建对象
Person p = (Person) c.newInstance("张三",23);
4.在Person类中成员变量为私有的,所以反射需要通过暴力来获取私有字段
Field f = clazz.getDeclaredField("name");
5.暴力获取到字段,需要去除私有权限>>>>修改成员变量
f.setAccessible(true);//去除私有权限
f.set(p, "李四");
6.输出p的结结果为
Person [name=李四, age=23]
完整代码:
public class demo5_Filed {
public static void main(String[] args) throws Exception{
//1.获取字节码文件
Class clazz = Class.forName("day8.Fac_Method.Person");
//2.获取有参构造
Constructor c = clazz.getConstructor(String.class,int.class);
//3.通过有参构造创建对象
Person p = (Person) c.newInstance("张三",23);
//4.获取name字段,即使私有也无关(暴力反射)
/*
Field f = clazz.getField("name");
f.set(p, "李四");//修改获取的成员变量
*/
Field f = clazz.getDeclaredField("name");//暴力获取私有的字段
f.setAccessible(true);//去除私有权限
f.set(p, "李四");//修改获取的成员变量
System.out.println(p);
}
}
1.5通过反射获取方法并且执行
1.根据1.3的Person类,完善Person类,添加了eat()方法【无参】
public void eat(){
System.out.println("今天吃了顿霸王餐");
}//如果是私有的方法需要暴力获取,本例不需要
2.获取字节码文件【Person】
Class clazz = Class.forName("day8.Fac_Method.Person");
3.获取有参构造
Constructor c = clazz.getConstructor(String.class,int.class);
4.通过有参创建对象
Person p = (Person) c.newInstance("张三",23);
5.通过getMethod获取Person类里的方法
Method m = clazz.getMethod("eat");
6.执行获取到的方法
m.invoke(p);
7.输出结果
今天吃了顿霸王餐
完整代码:
/**
* 无参执行方法
*/
public class demo6 {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("day8.Fac_Method.Person");
Constructor c = clazz.getConstructor(String.class,int.class);
Person p = (Person) c.newInstance("张三",23);
//获取eat方法
Method m = clazz.getMethod("eat");
//执行该方法
m.invoke(p);
}
}
1.根据1.3的Person类,完善Person类,添加了eat(int num)方法【有参】
public void eat(int num){
System.out.println("今天吃了"+num+"顿霸王餐");
}//如果是私有的方法需要暴力获取,本例不需要
2.获取字节码文件【Person】
Class clazz = Class.forName("day8.Fac_Method.Person");
3.获取有参构造
Constructor c = clazz.getConstructor(String.class,int.class);
4.通过有参创建对象
Person p = (Person) c.newInstance("张三",23);
5.通过getMethod获取Person类里的方法
Method m = clazz.getMethod("eat", int.class);//参数为字节码文件
6.执行获取到的方法
m.invoke(p, 3);
7.输出结果
今天吃了3顿霸王餐
1.6通过泛型擦除实现列表追加数据
public static void main(String[] args) throws Exception{
ArrayList<Integer> list = new ArrayList<>();
list.add(111);
list.add(222);
Class clazz = Class.forName("java.util.ArrayList");
Method m = clazz.getMethod("add", Object.class);//add方法的参数为Object类型
m.invoke(list, "abc");//执行
System.out.println(list);
}
结果
[111, 222, abc]
1.7反射练习
1定义一个Test_exec类;
2.写一个Properties格式的配置文件,配置类的完整名称;
3.写一个程序读取这个配置文件,获得完整名称并加载这个类,用反射运行run方法;
第一步:创建一个Test_exec类,里面包括run方法;
package day9_fanshe;
public class Test_exec {
public void run(){
System.out.println("Welcome to Bj");
}
}
第二步:创建配置文件xxx.properties,内容为Test_exec的完整路径
day9_fanshe.Test_exec
第三步:创建Test_demo类,通过反射执行run()方法
public class Test_demo {
public static void main(String[] args) throws Exception{
//1.创建流对象,读取配置文件
BufferedReader br = new BufferedReader(new FileReader("xxx.properties"));
//2.读取类名,获取字节码对象
Class clazz = Class.forName(br.readLine());
//3.通过字节码对象创建对象【无参】
Test_exec tc = (Test_exec) clazz.newInstance();
//4.调用方法
tc.run();
}
}
1.8反射之动态代理【很重要】
第一步:创建一个User接口;
通过UserImpl实现该接口
public interface User {
public void add();
public void delete();
}
public class UserImpl implements User {
@Override
public void add() {
System.out.println("添加功能");
}
@Override
public void delete() {
System.out.println("删除功能");
}
}
第三步:创建MyInvocationHandler类实现InvocationHandler【实现代理】
/**
* @author ZHENG
* 动态代理
*/
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
//执行被代理target的方法
method.invoke(target, args);
System.out.println("日志记录");
return null;
}
}
第四步:创建测试类,实现代码
public class Test {
public static void main(String[] args){
UserImpl ui = new UserImpl();
ui.add();
ui.delete();
System.out.println("===================");
/*
ui.getClass()获取字节码文件;
Proxy.newProxyInstance:接收的三个参数>>>>
* 第一个参数:所有类加载器;
* 第二个参数:所有接口
* 第三个参数:MyInvocationHandler这个类的子类对象
ui.getClass().getClassLoader()获取类加载器
ui.getClass().getInterfaces()获取所有的接口
*/
MyInvocationHandler m = new MyInvocationHandler(ui);
User u = (User) Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(),m);
u.add();
u.delete();
}
}
结果如下:
添加功能
删除功能
===================
权限校验
添加功能
日志记录
权限校验
删除功能
日志记录