反射
反射:在运行状态中,对于任何一个类都可以知道它的属性和方法
并且调用,包括私有的;
这种动态获取信息和动态调用对象方法的功能称为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();