定义
可以把接口理解为更彻底的抽象类。
如何使用接口
- 接口与类是平级的
也会编译为.class文件
- 关键字
interface - 声明
public interface Flyer{ }
接口的规则
- 接口中只有“全局静态常量”和“抽象方法"
- 全局静态常量
public static final int NUM = 100;
接口中的所有成员变量都默认是由public static final修饰。
- 抽象方法
public abstract void fly();
接口中的所有方法都默认是由public abstract修饰。
因此interface不能创建实例 (无构造器)
所以interface用以定义行为,被class实现(面向接口编程)
关键字: implements
实现:class Bird implements Flyer{}
- 实现接口的类称为“实现类”
- 若实现类实现了接口中“所有”的抽象方法,该类为具体类
若实现类没有实现接口中“所有”的抽象方法,该类必须是抽象类 - 接口可以继承接口,并且可以多继承接口,但是接口不能继承任何具体类
因为任何的具体类都会有一般方法,所以接口不能继承任何类 - 类只能单继承,但可以同时实现多个接口
class Bird extends Animal implements Flyer, Runner{ }
注意:先继承,后实现(先写extends,后写implements) - 接口支持多态
接口的作用
- 类可以多实现接口,解决了 Java 中单继承的局限性
- 接口定义了一种规范,可以定义一系列不相干事物的相同功能,大大提高了通用性
示例
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(Flyer.NUM);
// Flyer f = new Flyer();
Bird bird = new Bird();
bird.fly();
System.out.println(Flyer.NUM);
System.out.println(Runner.NUM);
System.out.println(bird.num);
Flyer f = new Bird(); //接口支持多态!
f.fly(); //虚拟方法调用
}
}
设计模式应用
- 工厂方法(FactoryMethod)
- 作用:用于创建对象的接口
- 概述:
FactoryMethod模式是设计模式中应用最为广泛的模式,在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却很重要。
FactoryMethod解决的就是这个问题,它通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略
- 代理模式(Proxy):宝强和宋吉
动态代理:
简单的说:
在启动核心方法时,拦截,在代理开始前后,做事情。
没有浸入到方法内部,却可以修改实际方法的任何细节。
比如:
在执行器中。返回个假结果。此时。另一头的核心方法执行时,将会拿到假结果。
也因为拦截,就可以在核心逻辑方法执行前,做其他辅助操作。使得核心逻辑方法可以
只编写核心的逻辑代码,完全解耦合。解决了硬编码的问题。
好处:完全解耦;
缺点:
1)实现复杂;不会写。
2)jdk提供的动态代理,被代理对象一定要实现接口;否则无法创建动态代理;
因为代理对象要代理对象的方法,并且,代理对象和被代理对象唯一的联系,就是接口!
package com.atguigu.inter;
/**
- 动态代理项目:计算器
- @author Mr.L
*/
public interface Calculator {
public int add(int i,int j);
public int sub(int i,int j);
public int mul(int i,int j);
public int div(int i,int j);
}
package com.atguigu.inter;
/**
- 项目:数学计算器+日志辅助
- @author Mr.L
*/
public class MathCalculator implements Calculator {
@Override
public int add(int i, int j) {
// 这输出就是日志辅助。但是目前我不得不硬编码在核心逻辑中。
// 如果,我还需要更加多的日志输出,将导致核心逻辑方法中,却编写了一大截无相关的代码。
System.out.println("运算开始了...");
int result=i+j;
// 这输出就是日志辅助。但是目前我不得不硬编码在核心逻辑中。
System.out.println("===>实际的内部add方法执行了:"+result);
return result;
}
@Override
public int sub(int i, int j) {
int result=i-j;
return result;
}
@Override
public int mul(int i, int j) {
int result=i*j;
return result;
}
@Override
public int div(int i, int j) {
int result=i/j;
return result;
}
}
package com.atguigu.test;
import org.junit.Test;
import com.atguigu.inter.Calculator;
import com.atguigu.inter.MathCalculator;
import com.atguigu.proxy.CalculatorProxyFactory;
public class AOPTest {
/**
* 使用动态代理,以完全解耦合,执行数学计算器。
* 1.活可以干好
* 2.核心逻辑方法中,只有核心逻辑代码。完全解耦合
* 3.执行实际方法时,可以做更多的事情。
* 可以改变实际方法的任何细节。瞒天过海。
*/
@Test
public void test1() {
//1.我们的实际对象
Calculator calculator = new MathCalculator();
//2.获取到的代理对象
Calculator proxy = CalculatorProxyFactory.getProxy(calculator);
//3.让代理对象帮忙干活
int add=proxy.add(1, 2);
System.out.println("计算结果:"+add);
}
/**
* 日志辅助,硬编码在核心逻辑中测试。
*/
@Test
public void test() {
Calculator calculator = new MathCalculator();
int add = calculator.add(1, 2);
System.out.println("计算结果:"+add);
}
}
package com.atguigu.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import com.atguigu.inter.Calculator;
import com.atguigu.util.LogUtils;
/**
-
代理工厂。帮我们生产代理对象。
-
@author Mr.L
-
王宝强:Calculator calculator
-
宋喆 :Calculator proxy
*/
public class CalculatorProxyFactory {//1.返回一个传入的对象的代理对象。
public static Calculator getProxy(final Calculator calculator) {
//4:提供Proxy类需要的三个参数
//①ClassLoader loader:被代理对象的类加载器
ClassLoader loader = calculator.getClass().getClassLoader();
//②Class<?>[] interfaces:被代理对象,所实现的所有接口
Class<?>[] interfaces = calculator.getClass().getInterfaces();
//③InvocationHandler handler :执行器
//6。分析清楚代理与被代理对象关系:然后关键的执行器:在执行期间,代理对象可以通过invoke执行被代理的方法;
InvocationHandler handler = new InvocationHandler() {
/**
* 7.分析并提供执行所需要的参数。
* Object proxy:宋喆
* Method method:正要执行的方法:执行实际方法
* Object[] args:方法执行时传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
//System.out.println("代理对象要帮你调用方法了...");
try {
//9.1 方法开始的时候记录一下日志;
LogUtils.logStart(method, args);
//method对象利用反射执行被代理对象的方法。调用后会有一个返回值
//obj:被代理对象:你宋喆再牛,上台表演还得王宝强。
result = method.invoke(calculator, args);
//9.2方法执行成功,返回值是多少。
LogUtils.logReturn(method, result);
} catch (Exception e) {
//9.3 如果出现异常了,输出e异常对象。
LogUtils.logException(method,e);
//甚至可以把异常都不输出。就算你1/0 照样给你定个结果。照样不报错6不6
//e.printStackTrace();
//return 10;
}finally {
//9.4 结束后。我就一定要你通知。
LogUtils.logEnd(method);
}
System.out.println(method.getName()+"方法正常返回,返回值:" + result);
//把真正执行的结果返回给外界。要不然宝强就给宋喆黑了。比如我不返回真的result.直接返回250.
return result;
//10。日志输出,以做好。但可以优化。把不同的日志提取。只在方法前后启动提取方法即可。
}
};
//3。动态代理的核心是:使用反射下的Proxy类:返回一个指定接口的代理对象。
//5。给了三个参数后,得到代理对象。返回。
Object proxy = Proxy.newProxyInstance(loader, interfaces, handler);
//2.放回一个代理对象。
return (Calculator) proxy;
}
}
package com.atguigu.util;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
- 日志优化
- @author Mr.L
*/
public class LogUtils {
//日志开始
public static void logStart(Method method,Object[] args){
System.out.println(method.getName()+"方法开始:参数表【"+Arrays.asList(args)+"】");
}
//日志方法正常返回
public static void logReturn(Method method, Object result) {
System.out.println(method.getName()+"方法正常返回:返回值:"+result);
}
//日志记录异常
public static void logException(Method method, Exception e) {
System.out.println(method.getName()+"方法出异常了。异常信息:"+e);
}
//方法结束
public static void logEnd(Method method) {
System.out.println(method.getName()+"方法最终结束。");
}
}
静态代理:
特征:
代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。
同时,每一个代理类只能为一个接口服务,如此程序开发中必然产生过多的代理。
如:
买房子 买手机
买房功能 (接口) 买手机功能 (接口)
链家网(决定有房没房) (代理类) 手机店/决定 (代理类)
买房者 (目标对象的类) 买手机者 (目标对象的类)
于是:
最好可以通过一个 代理类 完成全部的代理功能
网友评论