1. 什么是接口
接口是多个类的公共规范。
2. 接口的定义
public interface 接口名称 {
// 接口内容
// jdk1.7可以包含常量,抽象方法
// jdk1.8可以包含默认方法,静态方法
// jdk1.9可以包含私有方法
}
3. 接口的使用
接口的使用主要包含三部分
(1) 首先需要定义接口和接口中的抽象方法。
(2) 新建一个类,实现接口并重写接口中的所有抽象方法,此处需要注意,如果只部分重写了接口的抽象方法,那么该类需要定义为抽象类。
(3) 创建上述类对象,即可使用接口。
// 1. 定义接口和接口中的抽象方法
public interface MyInterface {
public abstract void method1();
public abstract void method2();
}
// 2. 新建一个类,实现接口并重写接口中的所有抽象方法
public class MyInterfaceImpl implements MyInterface {
@Override
public void method1() {
System.out.println("实现抽象方法1");
}
@Override
public void method2() {
System.out.println("实现抽象方法2");
}
}
// 3. 创建类对象,即可使用接口中的内容
4. 接口中的默认方法
现在假设接口的实现类MyInterfaceImpl已经投入使用了,但是现在要给接口加一个功能,比如加一个抽象方法,那么MyInterfaceImpl也需要重写新增的抽象方法,会造成一定的麻烦,而使用接口中的默认方法,则可以减少接口升级的麻烦。比如,我们现在接口中添加一个默认方法method3(),MyInterfaceImpl中不需要做任何改动,就可以用它的对象访问到method3(),实现了无感升级。当然,我们也可以在实现类中做对应的升级,即重写method3()。
public interface MyInterface {
public abstract void method1();
public abstract void method2();
public default void method3() {
System.out.println("接口中的默认方法");
}
}
public class InterfaceTest {
public static void main(String[] args) {
MyInterfaceImpl myInterface = new MyInterfaceImpl();
myInterface.method3(); // 输出"接口中的默认方法"
}
}
5. 接口中的静态方法
接口中静态方法的访问是直接通过接口来访问的,而不是通过实现类或者实现类的对象。另外一点需要注意的是,虽然接口中的静态方法不能被实现类重写,但是在实现类中可以存在一个完全同名同参的静态方法。
// 接口中静态方法定义
public interface MyInterface {
public static void method4() {
System.out.println("接口中的静态方法");
}
}
// 实现类中的同名同参静态方法
public class MyInterfaceImpl implements MyInterface {
public static void method4() {
System.out.println("实现类中的静态方法");
}
}
// 接口中静态方法使用
public class InterfaceTest {
public static void main(String[] args) {
MyInterface.method4(); // 输出"接口中的静态方法"
MyInterfaceImpl.method4(); // 输出"实现类中的静态方法"
}
}
6. 接口中的常量
接口中的变量只能是public static final修饰的,所以其实是常量,当然,public static final不写也没关系,默认被修饰为常量。此外,我们还需要注意,接口中的常量在定义的时候要赋值,并且一经赋值不可更改。
public interface MyInterface {
public static final int NUM = 10;
}
7. 一个类继承父类并实现多个接口
一个类只可以继承一个父类,但可以实现多个接口。比如,在下面的代码中,实现类继承了父类Father,并实现了接口A和接口B。在这种情况下,有可能会涉及到接口 - 接口,接口 - 父类之间同名方法的冲突。
(1) 第一种冲突是接口间抽象方法的冲突,可以看到在接口A和接口B中都抽象方法methodA(),此时实现类只需要重写一次methodA()。
(2) 第二种冲突是接口间默认方法的冲突,默认方法即使不重写,也可以通过实现类对象进行访问,但是当两个接口默认方法重名时,会出现不知道访问哪一个的情况,因此同名的默认方法必须要在实现类中重写。
(3) 第三种冲突是接口默认方法和父类普通方法的冲突,可以选择不重写,通过实现类对象访问的时候,优先调用父类中的方法;也可以重写,则调用重写后的方法。
// 接口A
public interface InterfaceA {
public abstract void methodA();
public abstract void methodB();
public default void methodC() {
System.out.println("接口A的默认方法C");
}
}
// 接口B
public interface InterfaceB {
public abstract void methodA();
public default void methodC() {
System.out.println("接口B的默认方法C");
}
public default void methodD() {
System.out.println("接口B的默认方法D");
}
}
// 父类
public class Father {
public void methodD() {
System.out.println("父类中的普通方法D");
}
}
// 实现类
public class InterfaceABImpl extends Father implements InterfaceA, InterfaceB {
@Override
public void methodA() {
System.out.println("同名抽象方法的重写");
}
@Override
public void methodB() {
}
@Override
public void methodC() {
System.out.println("实现类的默认方法C");
}
}
8. 接口和接口间的多重继承
之前提到了类 - 类之间只可以单继承,类 - 接口之间可以多实现,那接口 - 接口之间呢,其实是支持多重继承的。但是在多继承时有几点需要注意:
(1) 被继承的两个接口,比如接口A和接口B拥有同名抽象方法methodAbstract(),此时在继承的接口C中,不需要重写,只需要在接口C的实现类中进行抽象方法的重写即可。
(2) 被继承的两个接口,比如接口A和接口B拥有同名默认方法methodDefault(),此时在继承的接口C中,一定要重写该方法。
// 接口A
public interface InterfaceA {
public abstract void methodA();
public abstract void methodAbstract();
public default void methodDefault() {
System.out.println("接口A的默认方法");
}
}
// 接口B
public interface InterfaceB {
public abstract void methodB();
public abstract void methodAbstract();
public default void methodDefault() {
System.out.println("接口B的默认方法");
}
}
// 继承了接口A和接口B的接口C
public interface InterfaceC extends InterfaceA, InterfaceB {
public abstract void methodC();
@Override
default void methodDefault() {
System.out.println("接口C的默认方法");
}
}