首页 > 编程语言 >Java反射和代码

Java反射和代码

时间:2022-11-10 21:25:08浏览次数:51  
标签:反射 Class Java 代码 Object 代理 class 获取 public

反射

什么是反射

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

相关文章