JavaSE基础(三)反射

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();
	}
}

结果如下:

添加功能
删除功能
===================
权限校验
添加功能
日志记录
权限校验
删除功能
日志记录
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值