接口概念
接口 是一个抽象类型,是抽象方法的集合,以关键字 interface 来声明。一个类通过实现 (implements) 接口的方式,来实现接口的抽象方法。因此,接口可以理解为,对类定义进行了统一的格式规范。
接口的组成部分
抽象方法
抽象方法,就是只有方法声明,而没有具体的方法实现。
接口中的抽象方法会隐式指定为 public abstract,即接口内void test();
等价于public abstract void test();
并且也只可指定为 public abstract,指定其他修饰符会报错。
常量
接口中的字段(field)会被自动设置为 public static final,即静态常量。通过 接口.常量名
即可调用。字段指定为其他修饰符会报错。
默认方法
可以为接口方法提供一个默认实现,用 default 修饰符标记方法即可。
public interface Test {
default void test() {
System.out.println("这是一个默认方法");
}
}
默认方法的作用
- 提供方法的默认实现:实现接口时,只需要实现关注的方法即可(实现类的方法实现会覆盖接口方法的默认实现),不关注的方法不用实现,因为有默认实现。
- 接口演化:以 Collection 接口为例,这个接口作为 Java 的一部分已经有很多年了;在 Java 8 中,又为这个接口增加了一个 stream 方法。如果 stream 不是默认方法,那么接口增加 stream 方法后,所有实现类都要作修改;使用默认方法就可以解决这个问题,接口增加 stream 方法后,实现类也不会受到影响。
解决默认方法冲突
一个类继承了另一个类(父类),并同时实现了多个接口;这些接口有相同的默认方法(同名且有相同参数类型),父类中也有 同名且有相同参数类型 的具体方法。这个时候就会造成冲突,Java 中解决这种冲突的规则如下:
- 父类优先。如果父类提供了一个具体方法,接口中 同名且有相同参数类型 的默认方法会被忽略。
- 接口冲突。如果只是多个接口有相同的默认方法,父类没有 同名且有相同参数类型 的具体方法,那么必须在 接口实现类 中重写方法覆盖掉默认方法,在重写方法中可以使用
接口名.super.方法名
调用指定接口的默认方法。
public class MyClass implements A, B {
@Override
public void hello(int i) {
A.super.hello(i);
System.out.println("MyClass");
}
}
public interface A {
default void hello(int a) {
System.out.println("default A");
}
}
public interface B {
default void hello(int b) {
System.out.println("default B");
}
}
静态方法
接口中可以声明静态方法(有具体实现);使用 接口名.方法名
即可调用。
public interface A {
static void hi() {
System.out.println("hi");
}
}
接口与抽象类
在学习接口的时候是否有这样的疑惑,接口无非就是定义抽象方法,类实现接口来实现这些抽象方法;这个抽象类也能做,即抽象类定义抽象方法,类继承抽象类实现其中的抽象方法。这样接口是否显得很多余,似乎有抽象类就够了?
其实不然,因为存在这么一个问题:类的单继承机制,一个类继承一个抽象类后,就无法继承其他抽象类;而一个类可以实现多个接口,因此接口能够提供多继承的许多好处。
接口的特性
- 类不允许多继承,接口允许多继承,一个接口可以继承多个其他接口。
- 一个类只能继承一个类,但是能实现多个接口。
- 接口不能实例化,却能声明接口的变量,接口变量可以引用实现了接口的类对象。
- 实现接口时,抽象类可以不用实现所有的抽象方法,非抽象类必须实现所有的抽象方法。
- 接口中的所有方法自动地属于 public。因此,在接口中声明方法时,不必提供关键字 public。
- 默认方法可以调用接口中的任何其他方法,包括 抽象方法、默认方法、静态方法。
- 默认方法仍然是成员方法,需要通过对象(接口实现类的实例)调用,而不是如静态方法一般 直接通过接口调用。
接口的应用实例
Arrays 中有 sort 方法,可以对 对象数组进行排序;sort 有以下重载版本,可以传入 Comparator(比较器)自定义排序规则。public static <T> void sort(T[] a, Comparator<? super T> c)
现定义如下类实现 Comparator<String>
接口,使得字符串按照长度大小进行比较。
public class LengthComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}
当调用 sort 方法时,传入 LengthComparator 对象,即可实现字符串数组 按照长度由小到大进行排序。
public static void main(String[] args) {
String[] strs = {"bbbbb", "aa", "fff"};
Arrays.sort(strs, new LengthComparator());
for (String s : strs) {
System.out.println(s);
}
}
执行结果
aa
fff
bbbbb
当然,可以使用 lambda 表达式对代码进行简化,这样就不需要写一个类去实现 Comparator 接口了。Arrays.sort(strs, (s1, s2) -> s1.length() - s2.length());
如果有帮助的话,可以点个赞支持一下嘛
🙏