Java反射与动态代理

写在前面的话

俗话说,好记性不如烂笔头,学习的过程中,有些东西理解之后随着时间的推移记忆还是会消退,所以不如记录下来,帮助自己随时复习,这样才能深入理解。希望有一天我能将这些理解融入到骨子里,这样也许我就不用再来看这些东西了

Java的反射机制

Java的反射机制是在运行状态中,对于任意一个类,都能知道这个类中的所有属性和方法。对于任意一个对象,都能够调用它的任意一个方法或者属性。这种动态获取信息以及动态调用对象的方法的功能称为Java语言的反射机制

通过Java反射查看类信息

获取Class对象的三种方式:

package com.slience.enjoy;

public class Main {
	
	public static void main(String[] args) {
		Class<?> class1 = null;
//		try {
//			//第一种方式:通过Class类的静态方法forName实现
//			class1 = Class.forName("com.slience.enjoy.Book");
//			
//		} catch (ClassNotFoundException e) {
//			// TODO: handle exception
//		}
		
		//第二种方式:通过类的class属性
//		class1 = Book.class;
		
		//第三种方式:通过对象的getClass方法
//		Book book = new Book();
//		class1 = book.getClass();
		
		System.out.println(class1.getTypeName());
	}
}

获取class对象的成员变量

	private final static String TAG = "BOOKTAG";
	
	private String name;
	private String author;
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "Book{" +
		 "name='" + name + '\'' +
		 ", author='" + author + '\'' +
		 '}';
	}
			Field[] allFields = class1.getDeclaredFields();
			System.out.println("allFields.length = " + allFields.length);
			//获取class对象的public属性
			Field[] publicFields = class1.getFields();
			System.out.println("publicFields.length = " + publicFields.length);
allFields.length = 3
publicFields.length = 0
com.slience.enjoy.Book

此外还可以获取class的指定属性(class1.getDeclaredField(“xxx”))和指定public属性(class1.getField(“xxx”))

获取对象的方法

Method[] methods = class1.getDeclaredMethods();//获取class对象的所 有声明方法 
Method[] allMethods = class1.getMethods();//获取class对象的所有pub lic方法 包括父类的方法 
Method method = class1.getMethod("info", String.class);//返回次Cl ass对象对应类的、带指定形参列表的public方法 
Method declaredMethod = class1.getDeclaredMethod("info", String. class);//返回次Class对象对应类的、带指定形参列表的方法

获取对象的构造函数

Constructor<?>[] allConstructors = class1.getDeclaredConstructor s();//获取class对象的所有声明构造函数 
Constructor<?>[] publicConstructors = class1.getConstructors();//获取class对象public构造函数
Constructor<?> constructor = class1.getDeclaredConstructor(Strin g.class);//获取指定声明构造函数
Constructor publicConstructor = class1.getConstructor(String.cla ss);//获取指定声明的public构造函数

通过Java反射生成并操作对象

生成类的实例对象有两种方法:

	public static void main(String[] args) {
		
		try {
			Class<?> class1 = Class.forName("com.slience.enjoy.Book");
			//第一种方式:Class对象调用newInstance方法生成
			Object object = class1.newInstance();
			//第二种方式:获取Constructor对象,再通过Constructor对象的newInstance方法生成
			Constructor<?> constructor = class1.getDeclaredConstructor();
			Object object2 = constructor.newInstance();
			
			System.out.println("before method:" + object2.toString());
			Method method = class1.getDeclaredMethod("setName", String.class);
			method.invoke(object2, "Java从入门到放弃");
			Method method2 = class1.getDeclaredMethod("setAuthor", String.class);
			method2.invoke(object2, "xxx");
			System.out.println("after method:" + object2.toString());
			
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
before method:Book{name='null', author='null'}
after method:Book{name='Java从入门到放弃', author='xxx'}

当通过Method的invoke方法来调用对应的方法时,Java会要求程序必须有调用该方法的权限,如果程序确实需要调用某个对象的private方法,则可以先调用Method对象的setAccessible(boolean flag)方法,将Method对象的Accessible设置为true

代理模式

给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问, 即客户不直接操控原对象,而是通过代理对象间接地操控原对象,在软甲设计中,使用代理模式的意图很多,比如因为安全原因需要屏蔽客户端直接访问真实对象,或者在远程调用中需要使用代理类处理远程方法的调用技术细节,也可能为了提升性能,对真实对象进行封装,从而达到延迟加载的目的

代理模式的参与者

1.主题接口:Subjec是委托对象和代理对象都共同实现的接口,即代理类的所实现的行为接口,Request()是委托对象和代理对象共同拥有的方法
2.目标对象:RealSubject是原对象,也就是被代理的对象
3.代理对象:Proxy是代理对象,用来封装真实主题类的代理类
4.客户端:Client使用代理类和主题接口完成一些工作

实现接口
实现接口
代理
RealSubject目标对象
subject主题接口
Proxy代理对象
外部访问

静态代理的简单实现

package com.slience.enjoy;

//静态代理的重用性不强
public class Proxy {
	public static void main(String[] args) {
		RealSubject subject = new RealSubject();
		ProxySubject proxySubject = new ProxySubject(subject);
		proxySubject.request();
	}
}

interface Subject{
	void request();
}

class RealSubject implements Subject{
	@Override
	public void request() {
		// TODO Auto-generated method stub
		System.out.println("realSubject request");
	}
}

class ProxySubject implements Subject{
	
	private Subject subject;
	
	public ProxySubject(Subject subject) {
		// TODO Auto-generated constructor stub
		this.subject = subject;
	}
	
	@Override
	public void request() {
		// TODO Auto-generated method stub
		System.out.println("PreProgress");
		subject.request();
		System.out.println("PostProgress");
	}
}

PreProgress
realSubject request
PostProgress

动态代理相比静态代理的好处

  1. 不需要为主题对象写一个形式上完全一样的代理类。加入主题接口中的方法很多,为每一个对象写一个代理方法就很麻烦,如果接口有变动,则主题类和代理类都要修改,不利于维护
  2. 使用一些动态代理的生成方法可以在运行时制定代理类的执行逻辑,从而大大的提升了系统的灵活性

动态代理涉及到的反射类

  1. java.lang.reflect.Proxy:生成代理类的主类,是所有动态代理类的父类
  2. java.lang.reflect.InvocationHandler:调用处理器,它是一个接口,当调用动态代理类中的方法时,将会直接转接到执行自定义的InvocationHandler中的invoke方法

动态代理的简单实现

package com.slience.enjoy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxy {
	public static void main(String[] args) {
		//创建目标对象
		RealDSubject realDSubject = new RealDSubject();
		//创建调用处理器对象
		ProxyHandler handler = new ProxyHandler(realDSubject);
		//动态生成代理对象1
		DynamicSubject proxySubject = (DynamicSubject)Proxy.newProxyInstance(RealDSubject.class.getClassLoader()
				, RealDSubject.class.getInterfaces(), handler);
		//动态生成代理对象2:
//		Class proxySubject1 = Proxy.getProxyClass(RealDSubject.class.getClassLoader(), RealDSubject.class.getInterfaces());
//		Constructor constructor1 = null;
//		try {
//			constructor1 = proxySubject1.getConstructor(InvocationHandler.class);
//		} catch (NoSuchMethodException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} catch (SecurityException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		DynamicSubject proxySubject = null;
//		try {
//			proxySubject = (DynamicSubject)constructor1.newInstance(handler);
//		} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
//				| InvocationTargetException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		
		proxySubject.request();
		proxySubject.doSomething("eat food");
	}
}

interface DynamicSubject{
	void request();
	
	void doSomething(String s);
}

class RealDSubject implements DynamicSubject{

	@Override
	public void request() {
		// TODO Auto-generated method stub
		System.out.println("RealSubject request");
	}
	
	@Override
	public void doSomething(String s) {
		// TODO Auto-generated method stub
		System.out.println("RealSubject doSomething "+ s);
	}
	
}

class ProxyHandler implements InvocationHandler{
	
	private DynamicSubject s;
	
	public ProxyHandler(DynamicSubject s) {
		// TODO Auto-generated constructor stub
		this.s = s;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("before");
		Object result = method.invoke(s, args);
		System.out.println("after");
		return result;
	}
	
}

before
RealSubject request
after
before
RealSubject doSomething eat food
after
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值