接口和内部类为我们提供了一种将接口和实现分离的更加结构化的方法
抽象类和抽象方法
- 抽象方法:不完整,仅有申明而没有方法体。
abstract void f();
- 抽象类:
- 包含(一个或者多个)抽象方法的类。
- 是普通类和接口的中庸之道。
- 若继承抽象类并创建新类的对象,则
- 1)必须为基类中的所有抽象方法提供方法定义。
- 2)或者导出类也是抽象类(编译器强制我们用abstract限定该类)。
抽象类和抽象方法非常有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样使用他们。
抽象类还是很有用的重构工具,因为他们使得我们很容易将公共方法沿着继承层次结构向上移动。
接口
interface关键字使得抽象的概念更向前迈进了一步。它允许创建者确定方法名、参数列表和返回类型,但是没有提供方法体。即:接口只提供了形式,未提供任何具体实现。
接口的作用:
- 接口被用来实现类与类之间的协议。
- 实现完全解耦。
只要一个方法操作的是类而非接口,那么你只能使用这个类及其子类。如果你想要将这个方法应用于不在此继承结构中的某个类,那么你就触霉头了。接口可以在很大程度上放宽这种限制,因此,他使我们可以编写可复用性更好的代码。
接口和普通类相似点:
- 一个接口可以有多个方法。
- 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在 .class 结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
接口与普通类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法。
- 接口不能包含成员变量(除了 static 和 final 变量)。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。
接口和抽象类的区别:
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
Java中的多重继承:
interface CanFight { void fight(); }
interface CanSwim { void swim(); }
interface CanFly { void fly(); }
calss ActionMan { public void fight() {} }
class SuperMan extends ActionMan implements CanFight, CanSwim, CanFly {
public void swim() {}
public void fly() {}
}
public class Adventure {
public statiic void t(CanFight x) { x.fight(); }
public statiic void u(CanSwim x) { x.swim(); }
public statiic void v(CanFly x) { x.fly(); }
public statiic void m(ActionMan x) { x.fight(); }
public static void main(String[] args) {
SuperMan s = new SuperMan();
t(s); // SuperMan向上转型为CanFight
u(s); // SuperMan向上转型为CanSwim
v(s); // SuperMan向上转型为CanFly
w(s); // SuperMan向上转型为ActionMan
}
}
- 上述的例子是使用接口的核心原因:为了能够向上转型为多个基类(以及由此带来的灵活性)。
- 使用接口的第二个原因与使用抽象基类一样:防止客户端程序员创建该类的对象,并确保这仅仅是一个接口。
- 选哪个?
- 如果创建不带任何方法定义和成员变量的基类,就应该选择接口而非抽象类。
- 事实上,如果知道某事物应该成为一个基类,第一选择应该是的使他成为接口。