接口
基本格式
[可见度] interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
//接口类的实现
...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...
例子
package com.xxxx.helloworld;
//import java.lang.*;
//调用接口
public class Hello {
public static void main(String[] args) {
Helloimplements m = new Helloimplements();
m.sayHello("aaa");
}
}
//定义接口
interface IHello {
void sayHello(String name);
void sayGoogBye(String name);
}
//定义类
class Helloimplements implements IHello {
@Override
public void sayHello(String name) {
System.out.println("Hello " + name);
}
@Override
public void sayGoogBye(String name) {
System.out.println(name+" GoodBye!");
}
}
实际用途引入
- 假设我们需要在每次问候他人的时候做一个日志记录,这时候我们只需要在
Helloimplements
加一个写日志的方法即可,但是如果这个Helloimplements
是在封装好的JAR里面呢,我们没法修改代码呢?
静态代理
- 为了实现上述需求我们可以使用静态代理,创建一个新的类作为代理类,具体实现如下,虽然有点像继承,但是本质上还是有所区别,代理的是接口而非类。也就是将一个接口实例化成对象后传入代理类中,代理类相对应的(名称一致)的方法上进行调用对应方法,然后添加我们想增加的功能。这就是所谓的静态代理。
package com.xxxx.helloworld;
//import java.lang.*;
public class Hello {
public static void main(String[] args) {
Helloimplements m = new Helloimplements();
StaicProxy proxy = new StaicProxy();
proxy.setImpl(m);
proxy.sayHello("黄莉荃");
}
}
interface IHello {
void sayHello(String name);
void sayGoodBye(String name);
}
class Helloimplements implements IHello {
@Override
public void sayHello(String name) {
System.out.println("Hello " + name);
}
@Override
public void sayGoodBye(String name) {
System.out.println(name+" GoodBye!");
}
}
class StaicProxy implements IHello{
private IHello iHello;
public void setImpl(IHello impl){
this.iHello=impl;
}
@Override
public void sayHello(String name) {
System.out.println("logs:SayHello");
iHello.sayHello(name);
}
@Override
public void sayGoodBye(String name) {
System.out.println("logs:SayGoodBye");
iHello.sayHello(name);
}
}
动态代理
- 动态代理(dynamic proxy)同样需要一个代理类来代理接口,其中比较关键的是
newProxyInstance
这个方法来实现代理:
newProxyInstance
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException
- 参数:
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行
实例:
- 在代理类中使用一个bind方法来调用
newProxyInstance
,因为传入的是接口实例化后的对象,所以形参也是Object
类型,然后我们将newProxyInstance
返回的对象return.
public Object bind(Object delegate){ this.delegate = delegate; return Proxy.newProxyInstance( this.delegate.getClass().getClassLoader(),this.delegate.getClass().getInterfaces(),this); }
- 在代理类中使用一个bind方法来调用
InvocationHandler
- 和前面静态代理一样我们需要定义一个代理类,这个类需要
implements
InvocationHandler,我们在使用newProxyInstance
返回的对象调用相应的方法时候,InvocationHandler
会自动调用invoke
方法。所以在代理类里面需要定义一个invoke
方法。
invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("记录日志");
Object result = method.invoke(vehical, args);
return result;
}
- 参数
proxy:就是代理对象,newProxyInstance方法的返回对象
method:调用的方法
args: 方法中的参数
实例
package com.xxxx.helloworld;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Hello {
public static void main(String[] args) {
Helloimplements m = new Helloimplements();
DynaProxy proxy = new DynaProxy();
IHello ihello = (IHello) proxy.bind(m);
ihello.sayHello("黄莉荃");
}
}
interface IHello {
void sayHello(String name);
void sayGoodBye(String name);
}
class Helloimplements implements IHello {
@Override
public void sayHello(String name) {
System.out.println("Hello " + name);
}
@Override
public void sayGoodBye(String name) {
System.out.println(name+" GoodBye!");
}
}
class DynaProxy implements InvocationHandler{
private Object delegate;
public Object bind(Object delegate){
this.delegate = delegate;
return Proxy.newProxyInstance(
this.delegate.getClass().getClassLoader(),this.delegate.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy,Method method,Object[] args ) throws Throwable{
Object result =null;
try{
String originalName = method.getName();
if(originalName.equals("sayHello")){
System.out.println("logs:sayHello");
}else if(originalName.equals("sayGoodbye")){
System.out.println("logs:sayGoodbye");
}
result = method.invoke(this.delegate,args);
}
catch (Exception e){
e.printStackTrace();
}
return result;
}
}
分析
- 我们在bind处进行断点,可以看到
Helloimplements
对象传入。并赋值给delegate
- 跳到下一步可以看到调用了
Proxy.newProxyInstance
.
- 我们断点在
ihello.sayHello("黄莉荃");
可以看到虽然ihello
的静态类型是IHello
但是实际的数据类型是$Proxy0
.说明这个变量是被JVM加工过的。
- 当这个被JVM加工过的变量的
sayHello
或者sayGoodbye
方法被调用时候,将由JVM自动转交到invoke
下去。