Java基础(十三)——反射

反射

反射:在运行状态中,对于任何一个类都可以知道它的属性和方法
并且调用,包括私有的;
这种动态获取信息和动态调用对象方法的功能称为java的反射机制
反射是一种思想

类的加载

类的加载:
当程序需要使用某个类的时候,如果该类没有加载到内存中,
系统会通过加载,连接,初始化3个步骤来实现对这个类的初始化

加载:将class文件加载到内存中,并创建一个Class对象,
	任何类被使用时都会创建一个class对象
Object类的getClass方法,返回Object的运行时类
class的构成:成员变量,构造方法,成员方法
连接:
验证  	是否有正确的内部结构
准备 	负责为类的静态成员分配内存
解析	将类的二进制符号引用替换为直接引用
初始化:初始化
类加载器将class加载到内存中,并生成对应的Class对象
通过class对象就可以获取类的属性与方法

获取class对象的三种方式

获取Class文件对象的三种方法:
1.Object类中的getClass方法;
Student s = new Student ();
Class c = s.getClass(); 
2.数据类型的静态属性class
int.class
String.class
Student.class
3.Class类中的静态方法forName(类名)
Class c = Class.forName("全限定类名")
开发一般用第三种,可以将类名以配置文件的方式放入

Class类的方法:获取构造方法
public Constructor[]   getConstructor(Class<T>.....):获取单个的公共的构造方法,参数可变
public Constructors[]   getConstructors():获取所有的公共的构造方法
public Constructor[]<T>  getDeclaredConstructors():获取所有的构造方法(包括私有的)

利用class文件对象来创建对象
利用反射获取无参构造方法并运行
1.必须有无参构造
2.访问权限必须为public
class类的方法newInstance() 创建此class对象所表示的类的一个实例
	

利用反射获取有参构造方法并运行
1.必须有有参构造
2.访问权限必须为public
为有参构造传入参数
class对象.getConstructor(String.class【参数1的class】, int.class【参数2的class】);
class类的方法newInstance() 创建此class对象所表示的类的一个实例

Class的方法:获取成员变量
getField():获取单个公共成员变量
getFields():获取所有公共成员变量
getDeclaredField():获取单个成员变量(私有)
getDeclaredFields():获取所有的成员变量(私有)

Class类:获取所有的方法
getMethod();获取单个公共的方法,
getMethods();获取所有公共的方法,
getDeclaredMethod();获取单个的方法(包括私有)
getDeclaredMethods();获取所有的方法(包括私有)
public class Student {
	public String nameString;
	private int age;
	public Student(String nameString, int age) {
		super();
		System.out.println("有参构造器");
		this.nameString = nameString;
		this.age = age;
	}

	public Student() {
		super();
		System.out.println("无参构造器");
	}

	public void study() {
		System.out.println("学习中...");
	}

	private void show() {
		System.out.println("私有方法");
	}
	@Override
	public String toString() {
		return "Student [nameString=" + nameString + ", age=" + age + "]";
	}
}
/**
*Student提供公共与私有的属性
*公共与私有的方法
*/
配置文件config.properties:
className=reflace.Student
methodName=study

测试类

		//项目的绝对路径
		String path = new File(".").getCanonicalPath();
		//配置文件的相对路径
		String f = "src\\reflace\\config.properties";
		// IO流读取配置文件
		FileReader reader = new FileReader(new File(path, f));
		// 创建集合对象存储配置内容
		Properties properties = new Properties();
		properties.load(reader);//将配置文件数据存入集合中
		reader.close();
		// 获取类名
		String className = properties.getProperty("className");
		//获取方法名
		String methodName = properties.getProperty("methodName");
		
		// 反射获取class对象来调用有参构造器
		Class forName = Class.forName(className);
		Constructor constructor = forName.getConstructor(String.class, int.class);
		Object newInstance = constructor.newInstance("张三", 23);
		System.out.println(newInstance);
		//Student [nameString=张三, age=23]
		


		// 反射获取class对象来调用公共的方法
		Class forName = Class.forName(className);
		//创建student对象
		Object newInstance = forName.newInstance();
		//获取指定方法名的Method对象
		Method method = forName.getMethod(methodName);
		//调用student的方法
		method.invoke(newInstance);
	


		// 反射获取class对象来调用私有的方法
		Class forName = Class.forName(className);
		Object newInstance = forName.newInstance();
		Method declared = forName.getDeclaredMethod(methodName);
		declared.setAccessible(true);//取消权限检查
		declared.invoke(newInstance);
		//获取到的私有数据/私有方法/私有构造器都有setAccessible()
		//用于取消私有的访问权限的检查
	
	
		// 反射设置私有属性与公共属性
		Class forName = Class.forName(className);
		Object newInstance = forName.newInstance();
		Field declared1 = forName.getDeclaredField("age");
		Field declared2 = forName.getField("nameString");
		declared1.setAccessible(true);//取消权限检查
		declared1.set(newInstance, 23);//设置私有属性的值
		declared2.set(newInstance, "李四");//设置公共属性的值
		System.out.println(newInstance);

		

通过反射越过泛型的检查

ArrayList<String> arrayList = new ArrayList<String>();
只能添加STring不能添加Integer
伪泛型:编译后的class文件没有泛型
不用arrayList对象来调用add方法
用反射获取add方法来调用
ArrayList<String> arrayList = new ArrayList<String>();
Class class1 = arrayList.getClass();
Method method2 = class1.getMethod("add", Object.class);
method2.invoke(arrayList, 2);
System.out.println(arrayList);

动态代理

通过反射生成一个代理对象
java.lang.reflect反射包下的Proxy类和InvocationHandler接口,
通过这个类与接口可以生成动态代理对象
JDK提供的代理只能针对接口
对类做代理需要更加强大的代理cglib(框架中使用)
Proxy类的方法:创建动态代理对象
public static 	Object  newProxyInstance(ClassLoader  loader , Class<?> []  interfaces , InvocationHandler h)  :
最终会调用InvocationHandler的invoke方法
Object invoke(Object proxy , Method  method , Object [] argg)
//示例:
//在Student的方法前后加上权限校验与日志(简写版)
Student接口:
方法:find()
StudentImpl接口实现类:
方法:find();输出xxxx
MyInvocationHandler类实现InvocationHandler
重写invoke方法
private Object target;//目标对象
public MyInvocationHandler(object obj){
this.target = obj
}
三个参数:调用方法的代理实例,代理实例上调用接口方法的Method实例,方法的参数
public Object invoke(Object obj , Method method , Object[] args) throws Throwable{
system.out.println("权限校验");
Object result  =  method.invoke(obj,args);
system.out.println("日志记录")return result  ;//返回代理对象
}
package reflace;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
	private Students stu;

	public MyInvocationHandler(Students stu) {
		super();
		this.stu = stu;
	}

	public MyInvocationHandler() {
		super();
		// TODO Auto-generated constructor stub
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("权限校验");
		Object invoke = method.invoke(stu, args);
		System.out.println("日志记录");
		return invoke;
	}

}

测试类:

		Students students = new StudentsImpl();
		InvocationHandler handler = new MyInvocationHandler(students);// 对接口做代理
		Students stu = (Students) Proxy.newProxyInstance(students.getClass().getClassLoader(),
				students.getClass().getInterfaces(), handler);
		stu.find();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值