业精于勤荒于嬉,行成于思毁于随。
接口的作用
接口(interface) 实际上就是一种公共规范,对实现这个接口的类的一组需求。如同现实生活中的契约,规定了“你是…就应该能干…”。是一台汽车,就应该能跑。例如一个移动硬盘实现了USB接口,那它就应该能做USB接口规定要做的事,例如传输数据。 因此,接口中可以定义一些抽象的方法,来规定实现类需要做的事,如果一个类实现了这个接口,那这个类就需要覆盖重写这些抽象方法,来具体化方法的内容。
接口不能创建对象,因为接口的目的是对一个类做出规范,其本身无需实例化对象。
怎么实现接口
实现接口的关键字为 implements ,如果一个 Keyboard 类需要实现 Usb 接口:
public class Keyboard implements Usb {}
与类的单继承 不同的是,接口是多实现 的,一个类可以实现多个接口,中间用, 隔开:
public class Keyboard implements Usb, Bluetooth {}
接口之间也有继承关系,并且接口只能继承接口,而不能继承类。如果想让 Usb 接口继承 TypeC 接口,需要用到关键字extends ,写法如下:
public interface Usb extends TypeC {}
接口中可以包含哪些内容
public class Keyboard {
public static final int SIZE;
}
public ,static ,final 可以省略不写,接口中的成员变量默认为这三个关键字修饰。
public class Usb{
public abstract void close();
}
public ,abstract 关键字可以省略不写,效果相同。抽象方法用来规定类必须要做的事,因此是接口当中最重要的内容。如果一个类实现了接口,就必须重写接口当中的所有抽象方法,否则这个类自己必须是抽象类。
public class Usb{
public static void sayHello(){.
System.out.println("Hello");
}
private void printHello(){.
System.out.println("Hello");
}
}
Java8 以后,接口中可以使用静态方法 ,静态方法中的public 同样可以省略不写。 Java9 以后接口可以使用私有方法 ,私有方法 主要是给接口中的其他方法提供服务,对接口外隐藏。
public class Usb{
public default void start(){
System.out.println("开始!");
}
}
Java8以后接口中可以定义带有具体实现的默认方法 ,如上代码,public 关键字可以省略。 默认方法 主要用来解决接口的升级的问题,假设在很早之前就定义的一个接口,有大量用户在使用,而接口的设计者此时觉得需要增加一个新方法来扩展接口的功能,如果他给接口增加的是抽象方法,那么那些实现了该接口的类就不得不修改自己的代码来重写这个新的抽象方法,否则原来的代码就会报错。但是不见得每个人都需要这个新加的功能,所以接口的设计者就可以考虑使用默认方法。这样即使接口增加了功能,也不会影响到之前的实现类,倘若用户需要这个新功能,就可以覆盖重写这个默认方法,如果不需要也可以置之不理,而不用担心自己原先的代码受到影响。
不同接口中方法的冲突
接口中存在四种方法:抽象方法 ,静态方法 ,私有方法 ,默认方法 方法冲突指的是不同接口中提供了方法名称和参数列表都相同的方法,子类实现时就会造成矛盾。
抽象方法 无论如何都是要被实现类重写的(或者实现类是抽象类),所以多个接口抽象方法冲突也无关紧要。静态方法 是通过接口名称调用的,所以多个接口的静态方法冲突也互不影响。私有方法 为接口本身才能使用,对外隐藏,所以多个接口私有方法冲突也没有问题。 因此只需要讨论默认方法冲突的问题
-
超类具体方法与接口默认方法冲突 遵循超类优先的原则,如果超类提供了一个具体的方法,那么接口中同名且参数相同的默认方法会被忽略。 -
接口之间默认方法冲突 如果一个类同时实现的多个接口中存在冲突的默认方法,那么这个类必须重写冲突的方法,否则会报错。 -
接口间默认方法与抽象方法的冲突 人们很容易想当然的认为,既然一个方法是有具体实现的默认方法,另一个是没有方法体的抽象方法,那么实现类理应自动选择继承默认方法。很遗憾事实并非如此,Java设计者更强调一致性,两个接口如何冲突并不重要,只要两个冲突的方法有一个有具体实现,那么都会报错,程序员必须解决这个问题:自身申明为抽象类 或者 重写冲突的方法。
接口和抽象类的区别
虽然二者都有抽象方法用来规范类的行为,但是也存在一些差别。
- 接口当中不能有构造方法,抽象类可以有构造方法。
- 接口当中只能定义常量,抽象类可以定义实例字段。
- 一个类可以实现多个接口(多实现),但是只能继承一个抽象类(单继承)。
从第3点不难看出,因为类的单继承性,使用抽象类表示通用属性存在严重的问题:继承一个类之后,就无法再扩展第二个类了。但是多继承又会让代码和类的关系杂乱不堪且效率低下,比如C++,Eiffel。 但是接口的使用可以提供多重继承的大多数好处,同时还能避免多继承的复杂性和低效性。
|