接口定义
使用Interface关键字定义,接口定义的基本语法如下:
[修饰符] interface 接口名 extends 父接口1, 父接口2...
{
零个到多个常量定义...
零个到多个抽象方法定义...
零个到多个内部类、接口、枚举定义...
零个到多个默认方法或类方法定义...
//java9 新增的(零个到多个私有方法定义...)
}
对上面语法的详细说明:
- 修饰符可以是public或者省略,如果省略了public访问控制符,则默认采用包权限访问控制符,即只有在相同包下才可以访问接口。
- 接口名应该与类名采用相同的命名规则,即接口名只要是合法的标识符即可;遵循Java可读性规范,则接口名应由多个有意义的单词连缀而成,每个首字母大写,单词与单词之间无须任何分隔符。
- 一个接口可以有很多个直接父接口,但接口只能继承接口,不能继承类。
接口定义如下:
public interface Output {
//接口里定义的成员变量只能是常量
int MAX_CACHE_LINE = 50;
//接口里定义的方法只能是public的抽象方法
void out();
void getData(String msg);
//在接口中定义默认方法,需要使用default修饰
default void print(String...msgs) {
for (String msg : msgs) {
System.out.println(msg);
}
}
default void test() {
System.out.println("默认的test()方法");
}
//在接口中定义类方法,需要使用static修饰
static String staticTest() {
return "接口里的类方法";
}
/*Java9新增
//定义私有方法
private void foo() {
System.out.println("foo私有方法");
}
private static void bar() {
System.out.println("bar私有静态方法");
}
*/
}
接口的继承
接口的继承和类继承不同,支持多继承,即一个接口可以有多个直接父接口。和类继承相似,子接口扩展某个父接口,获得父接口里定义的所有抽象方法和常量。
一个接口继承多个父接口时,多个父接口排在extends关键字之后,多个父接口之间用英文(,)隔开。
如下代码:
interface InterfaceA{
int PROP_A = 5;
void testA()
}
interface InterfaceB{
int PROP_B = 6;
void testB()
}
interface InterfaceC extends InterfaceA , InterfaceB{
int PROP_c = 7;
void testC()
}
public class InterfaceTest{
public static void main(String[] args){
System.out.println(InterfaceC.PROP_A);
System.out.println(InterfaceC.PROP_A);
System.out.println(InterfaceC.PROP_A);
}
}
接口的使用
接口的主要用途:
- 定义变量,也可用于进行强制类型转换
- 调用接口中定义的常量
- 被其它类发现并使用
一个类可以实现一个或多个接口,继承使用extends关键字,实现使用implements关键字。因为一个类可以实现多个接口。
[修饰符] class 类名 extends 父类 implements 接口1 ,接口2 ...
{
类体部分
}
- 实现接口与继承父类相似,一样可以获得所实现接口里定义的常量(成员变量)、方法(抽象方法、默认方法)。
- 让类实现接口需要定义后面implements 部分,当需要实现多个接口时,多个接口之间以英文逗号(,)隔开。一个类可以继承一个父类,并同时实现多个接口,implements 部分必须放在extends部分的后面。
- 一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些方法);否则,该类将保留从接口那里继承到的抽象方法,该类也必须定义为抽象类。
- 一个类实现某个接口时,该类将会获得接口中定义的常量(成员变量)、方法等,因此可以把实现接口理解为一种特殊的继承,相当于实现类继承了一个彻底抽象的类(相当于除默认方法外,所有方法都是抽象方法的类)。
下面一个实现接口的类
//定义一个接口
interface Product{
int getProduceTime();
}
//Printer 实现Output和Product接口
public class Printer implements Output , Product {
private String[] printData = new String[MAX_CACHE_LINE];
// 记录当前需打印的作业数
private int dataNum = 0;
@Override
public int getProduceTime() {
return 45;
}
@Override
public void out() {
//只要还有作业就继续打印
while (dataNum > 0) {
System.out.println("打印机打印:" + printData[0]);
//把作业队列整体前移一位,并将剩下的作业数减1
System.arraycopy(printData, 1, printData, 0, --dataNum);
}
}
@Override
public void getData(String msg) {
if (dataNum >= MAX_CACHE_LINE) {
System.out.println("队列已满,添加失败");
}
else {
//把打印数据添加到队列里,以保存的数量加1
printData[dataNum++] = msg;
}
}
public static void main(String[] args) {
//创建一个PrintData对象,当成Output使用
Output o = new Printer();
o.getData("JavaEE 企业应用实战");
o.getData("java ");
o.out();
o.getData("Android");
o.getData("Ajax");
o.out();
//调用Output接口中的默认方法
o.print("齐天大圣", "天蓬元帅", "老妖精");
o.test();
Product p = new Printer();
System.out.println(p.getProduceTime());
//所有接口类型的引用变量都可以直接赋值给Object类型变量
Object obj = p;
}
}
实现接口方法时,必须使用public访问控制符,因为接口里的方法都是public的,而子类(相当于实现类)重写父类方法时访问权限只能更大或者相等,所以实现类实现接口里的方法只能使用public访问权限。 |
接口和抽象类相似和区别
相似
- 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。
- 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
区别
- 接口里只能包含抽象方法,静态方法、默认方法和私有方法,不能为普通方法提供方法实现;抽象类则完全可以包括普通方法。
- 接口里只能定义静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也可以定义静态常量。
- 接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
- 接口里不能包含初始化块;但抽象类则完全可以包含初始化块。
- 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足。