建立通用接口的唯一理由是,不同的子类可以用不同的方式表示此接口,通用接口建立起一种基本形式,一次表示所有导出类的共同部分,这就是抽象类(接口就是更纯粹的抽象类),该类的对象几乎没有任何意义,只是创建改接口的引用向不同的子类发送消息而已,所以设置了abstract关键字:创建抽象类的对象的时候编译不通过
一、抽象类
如果一个类中有抽象方法,那么该类也必须设置成abstract,而一个抽象类可以有0个或者多个抽象方法也可以有非抽象方法和字段。
二、接口
接口使抽象的概念更向前迈进了一步,他是一个完全的抽象类,他根本就没有具体的实现。它里面的字段默认都是 static final修饰的,方法默认都是 public abstract修饰的
接口中的域不能是空final
三、完全解耦
抽象类是继承概念,继承就代表他们是一个类型的东西
接口是实现概念,这个就是说明该类有接口的实现,也可以说有接口的功能
只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类,如果你想将此方法应用在不在此继承体系的某个类,那么就会不合适。
如果是接口,即使不在此继承体系中,只要实现了接口的方法的类也会适合该方法。从这个方面说接口更能解耦
Java中的设计模式更能说明这个问题:适配器模式
3.1 类适配器
我感觉这个用的非常少,这个要求适配器和要适配的类是一个体系,这里使用的情况就很少。
3.2 对象适配器
经典的设计模式,在实际情况中,你编写的类很难和调用者的类完全适配,这个时候你基本不会说修改你想要使用的类,因为代价太大,可能很对类对这个类有依赖。所以你需要对这个类进行包装,经过包装后,和调用者的类进行适配。
jdk经典的 InputStreamRead,就是对inputStream进行包装来适用Read。
3.3 接口适配器
经典的用法。很多时候接口的方法很多,但是我们只需要接口的一部分方法,这个时候你基本不会在创建一个类似的接口(只包含原来接口的部分方法),因为这样代码复用性不高,这个时候写一个抽象类对接口进行默认实现,这样创建新类的时候只要继承该抽象类,覆盖你想要的功能(方法即可)
四、java的多重继承
接口不仅仅是一种更纯粹的抽象类,他的目标比这更高
一个类可以实现多个接口,这也是使用接口的核心原因:为了能够向上转型为多个基类型
四、通过继承扩展接口
接口可以继承接口,而且可以继承多个接口
组合接口的名字冲突:
package com.hfview.interfaces.ExtendsInterface;
/**
* 组合接口的时候名字冲突。
* 这个很好理解,就按照方法重载理解就好了
*
* @author: zhw
* @since: 2019/3/6 16:01
*/
public class demoq {
}
interface I1{
void f();
}
interface I2{
int f(int i);
}
interface I3{
int f();
}
class C{
public int f(){
return 1;
}
}
/**
* 这个没问题,因为相当于方法重载
*/
class C2 implements I1,I2{
@Override
public void f() {
}
@Override
public int f(int i) {
return 0;
}
}
/**
* 这个没问题,因为相当于方法重载
*/
class C3 extends C implements I2{
@Override
public int f(int i) {
return 0;
}
}
/***
* 这个没问题,C就相当于I3的实现了
*/
class C4 extends C implements I3{
}
/*
直接报错了,因为这种方法重载的时候不能根据返回值来区分
class C5 extends C implements I1{
}*/
/*
直接报错了,因为这种方法重载的时候不能根据返回值来区分
class C6 implements I1,I3{
@Override
public void f() {
}
}*/
这个问题主要参考对方法重载的理解就可以
五、接口和类的选择
接口真的很诱人,动态绑定值真的很神奇,通过类能解决的都能用创建接口解决。所以这就引出了一个问题:改如何选择
恰当的原则是有限选择类而不是接口,从类开始,如果接口的必要性变得非常明确,那么久进行重构,接口是一种重要的工具,但是他们容易被滥用