Interface 接口
- Java不支持多继承,接口可以实现多继承效果
- 从几个类中抽取一些共同的行为特征, 他们之间没有 is-a 的关系
一、接口的使用
- 用Interface定义
- Java中接口和类是并列的结构
- 定义接口:定义接口中的成员
3.1 JDK7及之前:仅能定义全局常量和抽象方法
全局常量:public static final
抽象方法:public abstract
3.2 JDK8:除定义全局常量和抽象方法外,还可以定义静态方法、默认方法
interface Flyable{
//全局常量
public static final int MAX_SPEED = 7900;
int MIN_SPEED = 1;
//抽象方法
public abstract void fly();
void landing();
}
- 接口中不能定义构造器 -> 无法被实例化
- 接口的主要用途就是被实现类实现 -> implements ≠ extends
如果实现类覆盖了接口中的所有抽象方法, 则实现类就可以实例化
如果实现类没有覆盖了接口中所有抽象方法, 则实现类仍为一个抽象类
- 类可以实现多个接口
class SubClass extends SuperClass implements Interface1, Interface2, Interface3...{ }
- 接口与接口之间可以多继承
class Bullet extends Plane implements CC {
@Override
public void method1() {
}
@Override
public void method2() {
}
}
interface AA {
void method1();
}
interface BB {
void method2();
}
interface CC extends AA, BB {
}
- 接口具体的使用体现了多态性
- 接口实际定义了一种规范
public class UsbTest {
public static void main(String[] args) {
Computer com = new Computer();
// 1、创建了接口的 非匿名实现类*的 非匿名对象*
Flash flash = new Flash();
com.transferDate(flash);
// 2、创建了接口的 非匿名实现类*的 匿名对象*
com.transferData(new Printer());
// 3、创建了接口的 匿名实现类*的 非匿名对象*
USB phone = new USB() {
@Override
public void start() {
System.out.println("Phone starts to work");
}
@Override
public void stop() {
System.out.println("Phone ends working");
}
};
com.transferData(phone);
// 4、创建了接口的 匿名实现类*的 匿名对象*
com.transferData(new USB() {
@Override
public void start() {
System.out.println("MP3 starts to work");
}
@Override
public void stop() {
System.out.println("MP3 ends working");
}
});
}
}
interface USB {
void start();
void stop();
}
class Computer {
public void transferData(USB usb) { // USB usb = new Flash();
usb.start();
System.out.println("transfering");
usb.stop();
}
}
class Flash implements USB {
@Override
public void start() {
System.out.println("Flash start work");
}
@Override
public void stop() {
System.out.println("Flash end work");
}
}
class Printer implements USB {
@Override
public void start() {
System.out.println("Printer start work");
}
@Override
public void stop() {
System.out.println("Printer end work");
}
}
Flash starts to work
transfering
Flash ends working
Printer starts to work
transfering
Printer ends working
Phone starts to work
transfering
Phone ends working
MP3 starts to work
transfering
MP3 ends working
二、接口的应用
- 代理模式(Proxy)
1) 代理模式:为其他对象提供一种代理以控制对这个对象的访问
2) 应用场景
a. 安全代理:屏蔽对象真实角色的直接访问
b. 远程代理:通过代理类处理远程方法调用(RMI)
c. 延迟加载:先加载轻量级对象,真实对象看情况加载
Eg. 大文档中有许多大图片,打开文件时,不可能将所有图片都加载出来,当需要查看图片时通过proxy来进行大图片的打开
3) 分类
a. 静态代理:静态生成代理类
b. 动态代理:动态生成代理类 (JDK自带动态代理,需要反射知识)
4)具体代码
public class NetworkTest {
public static void main(String[] args) {
Server server = new Server(); // 创建被代理类对象
ProxyServer proxyServer1 = new ProxyServer(server); // 把被代理类对象传过去
proxyServer1.browse();
}
}
interface Network {
void browse();
}
// 被代理类
class Server implements Network {
@Override
public void browse() {
System.out.println("服务器Server访问网络");
}
}
// 代理类
class ProxyServer implements Network {
private Network work; // 创建接口类型对象
public ProxyServer(Network work) {
this.work = work;
}
public void check() {
System.out.println("联网前check");
}
@Override
public void browse() {
check();
work.browse();
}
}
联网前check
服务器Server访问网络
public class StaticProxyTest {
public static void main(String[] args) {
Star proxy = new Proxy(new RealStar());
proxy.confer();
proxy.bookTicket();
proxy.signContract();
proxy.sing();
proxy.collectMoney();
}
}
interface Star {
void confer();
void signContract();
void bookTicket();
void sing();
void collectMoney();
}
class RealStar implements Star {
@Override
public void confer() {
}
@Override
public void signContract() {
}
@Override
public void bookTicket() {
}
@Override
public void sing() {
System.out.println("RealStar Singing");
}
@Override
public void collectMoney() {
}
}
class Proxy implements Star {
private Star real;
public Proxy(Star real) {
this.real = real;
}
@Override
public void confer() {
System.out.println("Proxy confer");
}
@Override
public void signContract() {
System.out.println("Proxy signContract");
}
@Override
public void bookTicket() {
System.out.println("Proxy bookTicket");
}
@Override
public void sing() {
real.sing();
}
@Override
public void collectMoney() {
System.out.println("Proxy collectMoney");
}
}
Proxy confer
Proxy bookTicket
Proxy signContract
RealStar Singing
Proxy collectMoney
- 工厂模式
1) 工厂模式:实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
2) 面向对象的设计原则:
a. OCP (开闭原则 Open-Closed Principle):
软件实体应对扩展开放,对修改关闭。
控制需求变动风险,缩小维护成本
b. DIP (依赖倒转原则 Dependence Inversion Principle):
如果A中关联B,那么尽量使得B实现某个接口,然后A与接口发生关系,不与B实现类发生关联关系。(解耦调用与被调用者)
c. LOD (迪米特法则 Law Of Demeter):
类之间的直接联系尽量少,两个类的访问通过第三个中介实现
不和谋生人说话,有事找中介
3) 工厂模式的分类:
a. 简单工厂模式: 用来生产同一等级结构中的任意产品 (对于增加新的产品需要修改已有代码)
简单工厂模式也叫静态工厂模式, 工厂类一般是使用静态方法, 通过接收的参数不同, 返回不同的实例对象.
缺点: 对于增加的新产品, 不改代码的话是无法扩展的, 违反了开闭原则(对扩展开放, 对修改封闭)
b. 工厂方法模式: 用来生产同一等级结构中的固定产品 (支持增加任意产品)
c. 抽象工厂模式: 用来生产不同产品族的全部产品 (无法增加新产品, 只能增加新产品族)
抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度
public class FactoryTest1 {
public static void main(String[] args) {
// 创建者和调用者在一起
Car a = new Audi();
Car b = new BYD();
a.run();
b.run();
// 简单工厂模式 --调用者与创建者分离
Car factory1 = CarFactory.getCar("Audi");
factory1.run();
//工厂方法模式
Car car1 = new AudiFactory().getCar();
Car car2 = new BYDFactory().getCar();
car1.run();
car2.run();
}
}
interface Car {
void run();
}
class Audi implements Car {
@Override
public void run() {
System.out.println("Audi run");
}
}
class BYD implements Car {
@Override
public void run() {
System.out.println("BYD run");
}
}
// 简单工厂类
class CarFactory {
// 方式一
public static Car getCar(String type) {
if (type.equals("Audi")) {
return new Audi();
} else if (type.equals("BYD")) {
return new BYD();
} else {
return null;
}
}
// 方式二
public static Car getAudi() {
return new Audi();
}
public static Car getBYD() {
return new BYD();
}
}
//工厂方法模式
interface Factory{
Car getCar();
}
class AudiFactory implements Factory {
public Audi getCar(){
return new Audi();
}
}
class BYDFactory implements Factory {
public Car getCar(){
return new BYD();
}
}
- 错误举例
interface A {
int x = 0;
}
class B {
int x = 1;
}
class C extends B implements A {
public void pX() {
// System.out.println(x); //!! Reference to 'x' is ambiguous, both 'B.x' and 'A.x' match
// System.out.println(B.x); //!! Non-static field 'x' cannot be referenced from a static context
System.out.println(super.x); //调用B中的x
System.out.println(A.x); //调用A中的x
}
public static void main(String[] args) {
new C().pX();
}
}
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable, Bounceable {
Ball ball = new Ball("PingPang"); // public static final
}
class Ball implements Rollable {
private String name;
public String getName(){
return name;
}
public Ball(String name){
this.name = name;
}
public void play(){ // !
// ball = new Ball("Football"); //!! Cannot assign a value to final variable 'ball'
System.out.println(ball.getName());
}
}
- 练习:比较两个对象的大小
public class InterfaceTest2 {
public static void main(String[] args) {
ComparableCircle c1 = new ComparableCircle(3.4);
ComparableCircle c2 = new ComparableCircle(3.6);
int compareValue = c1.compareTo(c2);
if (compareValue > 0) {
System.out.println("c1 > c2");
} else if (compareValue < 0) {
System.out.println("c1 < c2");
} else {
System.out.println("c1 = c2");
}
}
}
interface CompareObject {
public int compareTo(Object o);
}
class Circle {
private Double radius;
public Circle(Double radius) {
this.radius = radius;
}
public Double getRadius() {
return radius;
}
public void setRadius(Double radius) {
this.radius = radius;
}
}
class ComparableCircle extends Circle implements CompareObject {
public ComparableCircle(double radius) {
super(radius);
}
@Override
public int compareTo(Object o) {
if (this == o) {
return 0;
}
if (o instanceof ComparableCircle) {
ComparableCircle c = (ComparableCircle) o;
// return (int)(this.getRadius() - c.getRadius()); // 错误!!! 强转精度损失
return this.getRadius().compareTo(c.getRadius()); // 属性声明为包装类时直接调用包装类的方法
} else {
throw new RuntimeException("数据类型错误");
}
}
}
三、JDK8中的接口
- 接口中定义的静态方法,只能通过接口调用
- 通过实现类的对象,可以调用接口中的默认方法
如果实现类重写了接口中的默认方法,调用时,调用的是重写的方法。 - 如果一个类继承的父类和实现的接口中存在同名同参数的默认方法,那么在子类没有重写的情况下,调用的是父类中的同名同参数方法。 --> 类优先原则
- 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写的情况下,会报错 --> 接口冲突
必须在实现类中重写此方法 - 在实现类中:
方法名(); -->调用本类中的重写的方法
super. 方法名(); -->调用父类中的方法
接口名.super. 方法名(); -->调用接口中的方法
public class InterfaceTest3 {
public static void main(String[] args) {
SubClass s = new SubClass();
// 接口中定义的静态方法,只能通过接口调用,不可以通过实现类调用
// s.method1();
Interface1.method1();
// 接口中定义的默认方法,可以通过实现类调用
// 如果实现类重写了接口中的默认方法,调用时调用的是重写后的方法
s.method2();
// --类优先原则
// 如果一个类继承的父类和实现的接口中声明了同名同参数的方法
// 那么子类在没有重写此方法的情况下,调用的是父类中的同名同参数方法
s.method3();
// 如果实现类实现了多个接口,多个接口中定义了同名同参数的默认方法
// 那么在实现类没有重写此方法的情况下会报错 --> 接口冲突
// 必须在实现类中重写此方法
// class SubClass2 implements Interface1, Interface2 {
//
// }
s.methodTest();
}
}
interface Interface1 {
// 静态方法
public static void method1() {
System.out.println("JDK8中接口可以定义有方法体的静态方法");
}
// 默认方法
public default void method2() {
System.out.println("JDK8中接口可以定义有方法体的默认方法");
}
default void method3() {
System.out.println("Interface1 method3()");
}
}
interface Interface2 {
default void method3() {
System.out.println("Interface2 method3()");
}
}
class SuperClass {
public void method3() {
System.out.println("SuperClass method3()");
}
}
class SubClass extends SuperClass implements Interface1, Interface2 {
public void method2() {
System.out.println("SubClass重写接口中的默认方法method2()");
}
public void method3() {
System.out.println("SubClass重写接口中的默认方法method3()");
}
public void methodTest() {
method3(); // 调用自己重写的method3()
super.method3(); // 调用父类中的method3();
Interface1.super.method3(); // 调用接口中的默认方法methon3()
}
}
四、抽象类和接口
- 相同点: 不能实例化, 都可以包含抽象方法
- 不同点: 1) 定义, 内部结构解释说明 2) 类, 单继承性 接口: 多继承 类和接口: 多实现
版权声明:本文为m0_46539410原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。