接口和类
《Thinking in Java》一书在《接口》一节中讲到——“接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法”。我认为接口其实是 一组抽象方法的集合,是一种极度抽象的类,但是他和类又有许多不同点。
接口与类的相似点
- 接口中可以有多个方法(也仅限于方法)
- 接口文件保存在 .java 结尾的文件中,文件名使用接口名,遵循类的命名方法。
接口与类的不同点
- 接口不能用于实例化对象,因此没有且无法定义构造方法。但接口中的方法可以被对象实现(类似于继承,但不是继承)。
- 接口中所有的方法都是抽象方法,即不能在接口中实现(无方法体)。每一个方法都是隐式抽象的,接口中的方法被隐式的指定为
public abstract
(只能是public abstract
,其他修饰符都会报错)。 - 接口中不能包含有成员变量(
static
和final
型变量除外)。如果在接口中定义变量,则会被隐式地定义为public static final
变量(并且只能是public
,用private
修饰会报编译错误)。 - 接口中不能含有静态代码块1以及静态方法(用
static
修饰的方法),而类(包括抽象类)是可以有静态代码块和静态方法。 - 一个类只能继承一个抽象类,但一个类却可以实现多个接口,并且接口支持多重继承。
接口的声明
声明接口需要使用interface
关键字——
[可见度] interface 接口名称 {
// 声明变量
// 抽象方法
}
//例如
public interface AnimalInterface {
public abstract void eat();//不需要写{},可省略abstract
public void sleep();
public void fight();
}
- 接口是隐式抽象的,当声明一个接口的时候,不必使用
abstract
关键字。 - 接口中每一个方法也是隐式抽象的,声明时同样不需要
abstract
关键字。 - 接口中的方法都是
public
公有的。
接口的实现
当一个类实现接口时,需要用implements
关键字。
...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...
//例如
public interface AnimalInterface {
public abstract void eat();//不需要写{},可省略abstract
public void sleep();
public void fight();
}
public class dog implements AnimalInterface {
public void eat(){
System.out.println("eat");
}
public void sleep(){
System.out.println("sleep");
}
public void fight(){
System.out.println("fight");
}
}
需要注意以下规则——
- 一个类只能继承一个类,但是能实现多个接口。
- 当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类(使用
abstract
)。 - 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
- 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。(暂时还不理解...)
接口的继承
一个接口能继承另一个接口,和类之间的继承方式比较相似,使用extends
关键字。继承和被继承的两个接口是可以定义相同的抽象方法的(不会报错...)。
[可见度] interface 接口名称 extends 其他的接口名 {
// 声明变量
// 抽象方法
}
//例如
public interface AnimalInterface {
public abstract void eat();//不需要写{},可省略abstract
public void sleep();
public void fight();
}
public interface DogInterface extends AnimalInterface{
public void bark();
public void tailShake();
}
// 此时如果一个类需要实现 DogInterface 接口的话需要总共实现五个方法。
- 虽然类的多重继承是不合法的,但是接口却可是实现多重继承。
public interface A {} public interface B {} public interface C extends A, B{}
标记接口
我们把不包含任何方法和变量的接口定义为标记接口。标记接口作用是是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。
public interface Flag{}
标记接口用于以下两个目的——
- 建立一个公共的父接口:正如
java.util.EventListener
接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener
接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。 - 向一个类添加数据类型:这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。