反射
什么是反射
Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到类对象之后,再通过类对象进行反编译,从而获取对象的各种信息。
获取类的3种方法
- 1、Class.forName("全类名"):将字节吗文件加载进内存,返回Class对象,多用于配指文件,将类名定义在配置文件中,便于利用java的反射机制生成类对象,加载类。
//加载一个用户实体类UserBean
Class c1 = Class.forName("com.test.UserBean");
- 2、类名.class:通过类名的属性class获取,多用于传递参数。
Class c2 = UserBean.class;
- 3、对象.getClass():多用于对象获取字节码的方式。
UserBean user = new UserBean();
Class c3 = user.getClass();
有了类就可以通过反射的方式来创建对象、操作属性和操作方法
通过类创建对象
- 1、使用newInstance()方法。
Object obj = stuClass.newInstance();
Student stu = (Student) obj;
- 2、反射获取构造函数,使用构造函数的方式创建对象。
Constructor<?> constructor = stuClass.getConstructor(int.class, String.class);
Object obj2 = constructor.newInstance(12, "23");
Student stu2 = (Student) obj2;
通过类获取构造器
方法 | 用途 |
---|---|
getConstructor(Class<?>... parameterTypes) | 获取与参数类型匹配的public类型的构造方法 |
getConstructors() | 获取所有的public类型的构造方法 |
getDeclaredConstructor(Class...<?> parameterTypes) | 获取与参数类型匹配的所有构造方法 |
getDeclaredConstructors() | 获取所有的构造方法 |
通过类操作属性
方法 | 用途 |
---|---|
getField(String name) | 获取某个public类型的属性 |
getFields() | 获取所有的public类型的属性 |
getDeclaredField(String name) | 获取某个属性对象 |
getDeclaredFields() | 获取所有的属性对象 |
// 获取类
Class<Student> stuClass = (Class<Student>) Class.forName("data.Student");
// 通过类实例化对象,对象属性都是空的
final Student student = stuClass.newInstance();
// 获取对象public修饰的属性
final Field score = stuClass.getField("score");
// 给属性赋值
score.set(student, 12);
// 获取对象private修饰的属性并赋值
final Field age = stuClass.getDeclaredField("age");
age.setAccessible(true);
age.set(student, 12);
通过类操作方法
方法 | 用途 |
---|---|
getMethod(String name, Class...<?> parameterTypes) | 获取与参数类型匹配的public类型的方法 |
getMethods() | 获取所有的public类型的方法(包含继承的方法 |
getDeclaredMethod(String name, Class...<?> parameterTypes) | 获取与参数类型匹配的所有方法 |
getDeclaredMethods() | 获取所有的方法 |
获取到函数后,我们可以使用invoke(Object obj, Object... args)
来调用对象的函数,并同时给其进行传参。使用getMethods()
来调用公有方法:
Class<Student> stuClass = (Class<Student>) Class.forName("data.Student");
final Student student = stuClass.newInstance();
final Method study = stuClass.getMethod("study");
study.invoke(student);
反射的使用
反射最大的作用就在于我们可以不在编译时知道某个对象的类型,而在运行时得到。同时我们只需要得到我们想得到的类的名字即可(如果不在一个包,必须写完整的名字包括包名)。
/**
成员变量:field对象(因为可能会有多个成员变量,一般用数组存储)
构造方法:Constructor Constructor[]
成员方法:Method Method[]
*/
public class Main {
public static void main(String[] args) throws Exception{
//返回A的构造方法
Constructor c = A.class.getConstructor();
//返回A类的所有为public 声明的构造方法
Constructor[] cons = A.class.getConstructors();
//返回A类所有的构造方法,包括private
Constructor[] cons2 = A.class.getDeclaredConstructors();
//返回A类的第一个public 方法
Method m = A.class.getMethod("say");
//执行
m.invoke(A.class.newInstance(), null);
//返回A类所有的public 方法
Method[] ms = A.class.getMethods();
//返回A类所有的方法,包括private
Method[] allMs = A.class.getDeclaredMethods();
//返回A类的public字段
Field field = A.class.getField("i");
System.out.println(field.get(A.class.newInstance()));
//返回A类的static 字段
System.out.println(field.get(null));
}
}
class A{
public int i = 1;
public static int b = 2;
public A(){
System.out.println("无参构造");
}
private A(String s){
System.out.println("有参构造"+s);
}
public void say(){
System.out.println("say");
}
}
代理
静态代理
静态代理需要先定义接口,被代理对象与代理对象一起实现相同的接口,代理类持有目标类的引用,然后通过调用相同的方法来调用目标对象的方法
举个栗子:
接口类 CarInterfaces.class,定义一组接口
interface CarInterfaces {
void run();
}
目标类 Car.class
public class Car implements CarInterfaces {
@Override
public void run() {
System.out.println("Car run()");
}
}
代理类 CarSystemProxy.class
public class CarSystemProxy implements CarInterfaces {
Car car;
@Override
public void run() {
System.out.println("before car run");
if (car == null) {
car = new Car();
}
car.run();
System.out.println("after car run");
}
}
当目标类接口增多后,代理类要代理新增的接口,如果按照静态代理的模式,代理类中要同步新增接口,这时候就显得比较麻烦
动态代理
动态代理与静态代理的区别主要在:
- 静态代理在编译时就已经实现
- 动态代理是在运行时动态生成的,在运行时动态生成类字节码,并加载到JVM中
两种常见的动态代理方式:JDK原生动态代理和CGLIB动态代理
JDK动态代理
JDK动态代理:Java自动生成代理类class对象,保存在内存中,通过反射获取代理类的构造方法,进而创建代理类的实例对象
public class RenterInvocationHandler<T> implements InvocationHandler{
//被代理类的对象
private T target;
public RenterInvocationHandler(T target){
this.target = target;
}
/**
* proxy:代表动态代理对象
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//代理过程中插入其他操作
System.out.println("租客和中介交流");
Object result = method.invoke(target, args);
return result;
}
}
CGLIB动态代理
CGLIB动态代理:也叫子类代理,通过在内存中构建一个子类,在子类用方法拦截的方式拦截所有父类方法的调用,然后加入自己的操作。因为使用的是继承,不能代理final类
public class ProxyFactory<T> implements MethodInterceptor {
private T target;
public ProxyFactory(T target) {
this.target = target;
}
// 创建代理对象
public Object getProxyInstance() {
// 1.cglib工具类
Enhancer en = new Enhancer();
// 2.设置父类
en.setSuperclass(this.target.getClass());
// 3.设置回调函数
en.setCallback(this);
return en.create();
}
//拦截方法
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("开始事务...");
// 执行目标对象的方法
Object result = method.invoke(target, args);
System.out.println("提交事务...");
return result;
}
}
标签:反射,Class,Java,代码,Object,代理,class,获取,public
From: https://www.cnblogs.com/d111991/p/16878820.html