Java动态代理的基本用法

简介

在开发中,我们可能会遇到一些类的方法不太合适我们实际的业务逻辑需求,而且我们不想或者不能修改该类的源码的时候我们通常会采用集成重写的方法去达到目标。
但是也有些情况下使用继承重写不是那么的方便,那么这个时候我们可以用java的动态代理技术去实现。

案例

本案例用来演示java动态代理可能不太合适,但是主要是为了演示动态代理的用法,所以不必过于纠结,我们主要看用法!

假设有一个类:猫,实现接口:动物。动物接口有三个方法~分别是:叫,睡,吃。
(之前看到一段代码,发现原来类名和方法名可以用中文来写,所以这里也用一下试试~)
public interface 动物 {
public void 睡觉();
public void 吃();
public void 叫();
}

public class 猫 implements 动物 {

	@Override
	public void 睡觉() {
		System.out.println("呼呼呼地睡觉");
	}

	@Override
	public void 吃() {
		System.out.println("呵呵呵呵地吃");

	}

	@Override
	public void 叫() {
		System.out.println("喵喵喵地叫");
	}

}

public class Main {

	public static void main(String[] args) {
		猫 cat = new 猫();
		cat.叫();
		cat.吃();
		cat.睡觉();

	}

}
运行结果:



猫实现”叫“方法的叫声笔者不太满意,因此笔者对此进行改造~我们可以使用动态代理这样改:

主要用Proxy这个类来实现,首先调用java.lang.reflect.Proxy的newProxyInstance方法~
动物  a=(动物) Proxy.newProxyInstance(猫.class.getClassLoader(), 猫.class.getInterfaces(), new InvocationHandler());
可以看到newProxyInstance接受三个参数,第一个是被代理的类加载器,第二个是被代理的类所实现过的接口数组(因为一个类可能实现了不止一个接口),第三个我们暂时不知道是什么来的,我们先new它出来~~我们再说说newProxyInstance的返回值,这个返回值是一个Object,但是我们知道猫实现了动物接口,所以我们可以用动物来接受这个返回值,同时耶因为返回值是一个object,所以在使用动物接收这个返回值的之前需要经过强转。

好了,写完这些之后发觉这句话还有错,一看发现InvocationHandler是一个接口,接口是不可以直接new的~因此我们再它后面加一对大括号~机智地把它变成一个匿名内部类~

动物  a=(动物) Proxy.newProxyInstance(猫.class.getClassLoader(), 猫.class.getInterfaces(), new InvocationHandler() {
			
			@Override
			public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
				
					return null;
			
				}
				
			}
		});

这里唯一未实现的方法就是invoke了,需要说一下的是:现在a对象可以用来调用吃,睡,叫这三个方法啦。但是a调用这三个方法的时候最终底层还是会调用刚才所实现的方法invoke~
为什么会这样?不急我们再看看invoke的参数,传入三个参数,一个参数是调用该方法的对象,第二个参数是a调用动物借口的方法~,第三个是a调用动物接口方法时所传进的参数~

根据这三个参数我们可以判断出a在外部到底要调用什么方法,在刚才实现的invoke方法里面进行简单的判断再做出相应的操作。
再回到我们的案例,我们最终的目的是改造猫的叫声:

public static void main(String[] args) {
		猫 cat=new 猫();
	
		
		动物  a=(动物) Proxy.newProxyInstance(猫.class.getClassLoader(), 猫.class.getInterfaces(), new InvocationHandler() {
			
			@Override
			public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
				if("叫".equals(arg1.getName())){
					System.out.println("汪汪汪叫");
					return null;
				}else{
					return arg1.invoke(cat, arg2);
				}
				
			}
		});
		a.叫();
		
	}

在invoke方法里面进行判断,如果方法名等于“叫”的话,则进行我想要的操作:输出”汪汪汪叫“。否则的话就调用猫原本的方法~
arg1.invoke(cat, arg2);

最后再说一下这个返回值,这个返回值是a调用实现接口的方法的返回值,如果没有返回值则直接返回null。

最后运行一下,就发现叫声已经变成狗叫啦~















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值