类,强调数据类型(自定义)的概念,在一些状况下,并不能反映对象以及对象操做的本质。有时咱们关注的并不是对象的类型,而是对象的能力。java
接口声明一组功能,做为协议(约定),可是自身不去实现功能方法。接口形式的交互涉及两方对象:一方实现接口,另外一方使用接口,双方并不直接依赖,而是针对接口编程。程序员
接口定义编程
接口定义即声明方法,制定功能协议。框架
Java 使用 interface
关键字声明接口,修饰符通常采用 public
。
接口内部声明方法时,一般不须要加修饰符,默认视为 public abstract
。ide
接口实现设计
类能够实现接口,表示类的对象具备接口(协议)制定的功能。code
Java 使用 implements
关键字实现接口。
实现接口必须实现接口中声明的全部方法。对象
public interface Printable { void print(); } public class A6 implements Printable { public void print() { System.out.println("Hello"); } public static void main(String args[]) { A6 obj = new A6(); obj.print(); } }
接口扩展继承
接口能够扩展另外一个接口甚至多个接口,其方式与类能够扩展(继承)另外一个类的方式相同,使用 extends
关键字,可是类的继承限制为单继承。接口
public interface BallGame extends Sport, Match {}
类的继承与接口实现能够共存,而且类能够实现多个接口,从某种形式上构成多继承结构。
public class Football extends Ball implements Sport, Match {}
等价于:
public class Football extends Ball implements BallGame {}
接口使用
与类不一样,没法直接 new 建立接口对象,可是能够声明接口类型的变量,引用实现了接口的类对象。
public interface Printable { void print(); } public class Main { public static void main(String args[]) { Printable obj = new Printable() { @Override public void print() { System.out.println("Hello"); } } obj.print(); } }
上述代码看似建立接口对象,实则建立匿名内部类对象,由其实现接口。
接口有时更能反映出对象的本质(能力,一组功能协议)。所谓针对接口编程,使用接口而非具体实现接口的类型,统一处理不一样类型对象,旨在下降耦合性,提升灵活性。固然,接口自己因为没有代码实现,并无太大用处,须要依赖具体实现,才能生效。
抽象类,顾名思义抽象的类,通常表明多个具体类(子类)上层公共的父类,做为基类统一调用接口(方法)。
抽象方法和抽象类密不可分,抽象方法是未来做为统一接口调用,而目前不知道如何实现的方法,只有经过子类重写方法才能具体实现功能。
抽象类 Animal
定义 sound()
方法做为统一接口调用,由于没法肯定 sound()
方法该如何具体实现,Java 使用 abstract
关键字声明方法为抽象方法,无需定义方法体。子类 Dog
继承抽象类 Animal
,并具体实现 sound()
方法。
//abstract parent class abstract class Animal { //abstract method public abstract void sound(); } //Dog class extends Animal class public class Dog extends Animal { public void sound() { System.out.println("Woof"); } public static void main(String args[]) { Animal obj = new Dog(); obj.sound(); } }
区别于具体类,抽象类没法直接 new 建立抽象类对象,可是能够声明抽象类的变量,引用抽象类对应具体子类对象。
抽象类介于接口和类之间。
相同点
不一样点
对比条件 | 接口 | 抽象类 |
---|---|---|
构造器 | 不存在 | 能够有 |
具体方法 | 不存在 | 能够有 |
实例变量 | 不存在 | 能够有 |
“多继承” | 支持 | 不支持 |
接口 = 纯抽象类(全部方法都是抽象方法)
应用场景
考虑多态性、统一接口调用的同时,须要实例变量、带有默认实现的具体方法,使用抽象类。
声明一组方法,却又不想每一个具体类都实现全部方法,可使用抽象类,借助空方法,交由具体类自行决定重写其感兴趣的方法。
具体类已经有父类,受 Java 限制只容许单继承,只能选择经过实现接口方式扩展类。
《Effective Java》中讨论到一条规则:“接口优于抽象类”。基于以下论断:
- 现有的类能够很容易被更新,以实现新的接口。
通常来讲,没法更新现有的类来扩展新的抽象类。若是但愿让两个类扩展同一个抽象类,就必须把抽象类放到类型层次的高处,这样会间接地伤害到类层次,迫使这个公共祖先的全部子类都扩展这个新的抽象类。- 接口是定义 mixin(混合类型)的理想选择。
混合类型除了自身类型以外,还能够提供某些可选择的行为。例如,实现 Comparable 接口的实例之间能够相互比较。- 接口容许咱们构造非层次结构的类型框架。
类型层次对于组织某些事物是很是合适的,可是并不是全部事物都能被整齐地组织成一个严格的层次结构。类层次过于臃肿缺少灵活性,经过接口扩展行为,必定程度上模拟多重继承。
P.S. Java 限制只容许单继承,即类不可能有一个以上的父类。
规则存在例外,即当演变的容易性比灵活性和功能更为重要的时候,应该使用抽象类来定义类型。抽象类的演变比接口的演变要容易得多,当在抽象类中增长新的具体方法,它包含合理的默认实现,该抽象类的全部现有实现都将提供这个新的方法。接口一旦被公开发行,而且已被普遍实现,再想改变这个接口几乎是不可能的。当在公有接口中增长方法,不可避免破坏实现这个接口的全部现有的类。
书中建议程序员为“每一个重要接口都提供一个抽象的骨架实现(skeletal implementation)类,把接口和抽象类的优势结合起来。接口的做用仍然是定义类型,可是骨架实现类接管了全部与接口实现相关的工做。”
Java 类库中存在许多一个接口对应一个抽象类的设计,例如:Collection 接口与 AbstractCollection 抽象类、List 接口与AbstractList 抽象类...。
抽象类和接口是配合而非替代关系。接口声明能力,抽象类提供默认实现(所有或部分方法)。