本章介绍如何使用接口定义行为,以及如何使用接口的多态;枚举常数与enum枚举与接口结合。
目录
一、接口
1.接口定义行为
继承是is-a的关系,子类可以继承父类并使用父类的方法,那如果我们需要共用一个方法,但不是is-a的关系,该如何操作呢,何不把行为方法直接封装在一个类里呢,于是接口顺应而生。
接口里的行为表示被所有东西拥有。
在Java里用interface关键字定义。接口只能定义行为,但不定义操作。因此,方法直接标识为abstract,权限为pubic。
类操作接口用implements关键字,操作某个接口,对定义方法只有两种选择,一是操作接口中定义的方法,二是再度将该方法标识为abstract。
以Java的逻辑语意来说,继承是“是一种”的关系,而接口是“拥有行为”的意思。
在JDK8之前按照这个逻辑语意使用较为清晰。但其实,Java接口也是支持多重继承的一种方式,在JDK8之后为了引入Lambda新特性,放宽了对接口的一些限制,在之后的相关章节会再细说。
2.行为的多态
在判断多态语法时,我们又需要用试着把自己当编译程序进行逻辑判断了。判断方式:右边是不是拥有左边的行为,或是不是操作了左边的接口。必要时候,我们还是会需要扮演(Cast)语法,只要在执行时期绑定的是同一对象实例就不会出错,或者绑定的是其对象的父类也不会出错。
在继承中使用多态,我们设计的方式是使用父类对象作参进行使用,每个子类都可以使用父类的方法;在接口中,我们可以直接把接口类的对象作参使用。只要是操作这个接口的对象,都可以使用这个方法。
3.解决需求变化
在生活实践中,我们会应对很多来自客户或是上级的需求变化,因此我们写的代码必须具有弹性和可维护性,这要求我们的程序要有优秀的设计架构。
对于类,类不能多重继承,但类可以操作多个接口;类还可以继承的同时再操作接口;而对于接口,接口可以继承接口,即继承父接口;还可以继承两个以上接口,即多重继承接口。
二、接口语法细节
1.接口的默认语法
之前说接口的方法需要是public abstract修饰,在编写时为了方便,可以省略式书写,但编译程序会在编译的时候补上。
接口中的方法默认权限即public,而类中的方法如果不书写权限修饰符,默认是包权限default。所以在都缺省的情况下,用类操作接口的方法时,则会权限不够,编译失败。
2.匿名内部类
在编写Java程序时,经常会需要临时继承某个类或操作某个接口并建立实例的需求,而对于这种类或者接口只使用一次,因而我们可以为这些类定义名称,这个语法叫作匿名内部类(Anonymous Inner Class),语法如下:
new 父类() /接口(){ // 类本体操作 }
如果要在匿名内部类中使用变量,在JDK8之前必须将变量定义为final,JDK8之后不用强调书写,但实质也是final。
3.枚举常数
在Java接口中会经常看到定义这类public static final的常数。这叫作枚举常数。比如可以使用在switch语法等等在编写程序时会更清晰和可维护。为了编写方便,可以直接省略前面的修饰,事实上在接口里定义的变量值都不可修改。
在JDK5之后新增了enum语法,实际上enum定义了一个特殊的类,继承自java.lang.Enum,这是编译程序处理的,我们不能继承,否则报错。
public enum Action{
STOP,RIGHT,LEFT,UP,DOWN
}
经过反编译,我们可以了解enum枚举常数的部分细节
public final class Action extends Enum{
private Action(String s,int i){
super(s,i);
}
public static final Action STOP;
……
……
public static final Action DOWN;
static{
STOP=New Action("STOP",0);
……
}
}
结论:用enum定义的是特殊类,定义的枚举常数都是public static final,而且是这个类的实例。而且这个类的构造函数是private,也就是说只能在类中才可以实例化,在类外使用时,我们只能传入Action实例、声明Action以及在switch-case语法中列举Action实例。关于更多自定义枚举,日后会详细说。