一、接口的概念
如果抽象类中的所有方法都是抽象方法就可以把这个抽象类转成接口来表示,接口本质不是类。接口是功能的集合。
关键字interface声明一个接口,接口不是类,而是一组对类的需求描述。接口使抽象的概念更进一步,接口就像是一个生产类的工厂模具,实现类都必须按照他的要求去编译,或者说接口是建立类的协议。
二、接口的特性
1)接口不能new一个对象,它不是类;
2)接口的方法没有方法体body,既不能有{};
3)实现类使用关键字implements实现对应接口。实现类必须重写接口的所有抽象方法,如果不想都重写就要把这个类变成抽象类;
4)接口的所有修饰符只能为public;
5)接口不能定义构造方法,也不能创建对象,接口对象可以利用子类对象(实现类)的向上造型进行实例化;
6)声明的接口类型对象在编译时期可以接收所有类型对象的赋值,但是在运行时期仍然检测接收的对象类型是否是接口的实现类,也就是其他类型的对象转成接口类型时编译时期不检测,运行时期检测是否具有实现关系;
7)接口不能有变量但是可以定义常量,常量默认被public static final共同修饰,本质是个全局常量;
8)接口可以有多个实现类,实现类也可以引用多个接口,但抽象类的子类只能继承一个父类(java支持多实现,接口与接口之间支持多继承,类与类之间是单继承)。
三、一个简单接口的实例
//接口
interface Shape extends Cloneable,Serializable{
public abstract double getGirth();
public abstract double getArea();
}
//实现类
class Rectangle extends Object implements Shape,Cloneable{
@Override
public double getGirth(){
return 0.0;
}
@Override
public double getArea(){
return 0.0;
}
}
四、接口与抽象类
为什么有了抽象类,设计人员还要不予余力的引入接口概念呢?
首先考虑的是抽象类的局限性。子类只能继承一个父类,而实现类可以引入多个接口,在实际项目中当要改动一些方法的body,无需删除本来的代码,从新写一个实现类,更换接口引用的对象即可。
其次是接口的松耦合是我们可以编写可复用性高的代码。比如Server层本来引用使用Dao层mysql数据库的实现类,现在遇到mysql解决不了的业务,需要orcale实现,难道你要为了这一个或几个的功能,把所有的引用mysql的全删掉重写?只要再写一个dao层的实现类去引用这个接口,遇到需要orcale方法使用哪个接口变量就好了,别人写的代码也无需去删改。抽象类可以再写一个子类,但子类却不受父类过多约束,随意添加方法,对于项目的协同工作不利。抽象类做不到“对修改封闭,对扩展开放”的原则。
再者接口更加安全,严密,接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些。对于开发,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口不仅告诉开发人员你需要实现那些业务,而且也将命名规范限制住了(防止一些开发人员随便命名导致别的程序员无法看明白)。
继承抽象类——扩充类的继承结构
实现接口——加入更多的新特性
五、接口回调
我对接口回调的理解就是:回调方类A的一个方法a通过调用类B的一个方法b去调用类A的另一个方法c。绕晕了吧,其实就是一个类去请求另一个类后得到回复再去调用本类的另一个方法,至于同步回调就是方法b中的逻辑执行完再去执行方法c,而异步回调就是b和c一起再执行。有人问:为什么不直接通过a去调用c呢?答案很简单,生活中有些事总不能自己解决,学生有问题总不能自问自答吧。下面是一个乘客与司机的同步回调案例:
interface Callback{ //回调方类A的接口
boolean Consider(int money); //思考是否付钱,就是方法c
void PayFor(int money); //付钱,就是方法c
}
class TaxiDriver{ //调用方类B
public int Answer(Callback callback){ //回答多少钱,就是方法b
System.out.println("去那的话要100块");
if(callback.Consider(100) == true){
callback.PayFor(100);
}
return 100;
}
}
class Passenger implements Callback{ //回调方类A
@Override
public boolean Consider(int money) {
boolean result = true;
if(money > 80){
System.out.println(money+"太贵了,您看80行不行?");
result = false;
}
return result;
}
@Override
public void PayFor(int money) {
System.out.println("好的,这是您的"+money);
}
public void TakeTaxi(TaxiDriver td){ //询问多少钱,就是方法a
System.out.println("师傅,去天一多少钱?");
td.Answer(this);
}
}
public class CallBackTest {
@Test
public void test(){
TaxiDriver td = new TaxiDriver();
Passenger passenger = new Passenger();
passenger.TakeTaxi(td);
}
}
运行结果如下:
乘客问老司机去天一多少钱,老司机狮子大开口,乘客嫌贵,再和他谈谈。这就是一个同步回调,之所以同步原因很简单,你总不能在没有得到多少钱就直接上车吧?这可不是去幼儿园的车。
我们解析一下:首先类Passenger实现接口Callback中的考虑Consider和付钱PayFor这两个需要得到类TaxiDriver回答是否要调用的方法,还有一个非接口的方法打车TakeTaxi的方法。方法TakeTaxi中以类TaxiDriver为参数来调用TaxiDriver的方法Answer(),并将自己的this传给方法Answer(),而方法Answer()呢又是以接口Callback为参数,刚好获得类Passenger的this,先自己给出价格,再将价格通过this传给Passenger的方法Consider,可惜老司机太贪,不然还可以接着调用方法PayFor();
示意图如下:
至于异步回调就是在方法b中新开一个线程来调用方法c,方法body中调用c的代码与其他代码同时编译
public int Answer(Callback callback){ //回答多少钱,就是方法b
System.out.println("去那的话要100块");
new Thread(new Runnable() {
@Override
public void run() {
if(callback.Consider(100) == true){
callback.PayFor(100);
}
}
}).start();
return 100;
}
当然本例不适合异步,但是你想想,万一这里有还几个司机,你问完司机A,在等待结果的时候再去问司机B,就适用于异步回调了。当然要实现这个场景需要改的可不止方法Answer(),同时要给司机类抽象化,方法TakeTaxi也要写进接口Callback中,因为你不是还有在通过this调用它去问另一个司机嘛。
我认为学习离不开生活,越高大上的反而越从生活中得到启发,多想想生活中的实例,才会更好的理解代码,代码也能更好的为生活服务
参考:https://blog.csdn.net/qq_33667439/article/details/78666979