接口的细节
-
- 1、接口中的变量
- 2、接口的继承
- 3、类的继承与接口
- 4、instanceof
- 5、使用接口替代继承
- [6、Java 8和Java 9对接口的增强](#6、Java 8和Java 9对接口的增强)
1、接口中的变量
接口中可以定义变量,语法如下所示:
java
public interface Interface1 {
public static final int a = 0;
}
这里定义了一个变量int a,修饰符是public static final,但这个修饰符是可选的,即使不写,也是public staticfinal。这个变量可以通过"接口名.变量名"的方式使用,如Interface1.a。
2、接口的继承
接口也可以继承,一个接口可以继承其他接口,继承的基本概念与类一样,但与类不同的是,接口可以有多个父接 口,代码如下所示:
java
public interface IBase1 {
void method1();
}
public interface IBase2 {
void method2();
}
public interface IChild extends IBase1, IBase2 {
}
3、类的继承与接口
类的继承与接口可以共存,换句话说,类可以在继承基类的情况下,同时实现一个或多个接口,语法如下所示:
java
public class Child extends Base implements IChild {
//主体代码
}
关键字extends要放在implements之前。
4、instanceof
与类一样,接口也可以使用instanceof关键字,用来判断一个对象是否实现了某接口,例如:
java
Point p = new Point(2,3);
if(p instanceof MyComparable){
System.out.println("comparable");
}
5、使用接口替代继承
继承至少有两个好处:一个是复用代码;另一个是利用多态和动态绑定统一处理多种不同子类的对象。
使用组合替代继承,可以复用代码,但不能统一处理。使用接口替代继承,针对接口编程,可以实现统一处理不同类型的对象,但接口没有代码实现,无法复用代码。将组合和接口结合起来替代继承,就既可以统一处理,又可以复用代码了。
先增加一个接口IAdd,代码如下:
java
public interface IAdd {
void add(int number);
void addAll(int[] numbers);
}
修改Base代码,让它实现IAdd接口,代码基本不变:
java
public class Base implements IAdd{
private static final int MAX_NUM = 1000;
private int[] arr = new int[MAX_NUM];
private int count;
public void add(int number) {
if(count < MAX_NUM) {
arr[count++] = number;
}
}
public void addAll(int[] numbers) {
for(int num : numbers) {
add(num);
}
}
}
修改Child代码,也是实现IAdd接口,代码基本不变:
java
public class Child implements IAdd{
private Base base;
private long sum;
public Child() {
base = new Base();
}
public void add(int number) {
base.add(number);
sum += number;
}
public void addAll(int[] numbers) {
base.addAll(numbers);
for(int i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
}
public long getSum() {
return sum;
}
}
Child复用了Base的代码,又都实现了IAdd接口,这样,既复用代码,又可以统一处理,还不用担心破坏封装。
6、Java 8和Java 9对接口的增强
需要说明的是,前面介绍的都是Java 8之前的接口概念,Java 8和Java 9对接口做了一些增强。在Java 8之前,接口中的方法都是抽象方法,都没有实现体,Java 8允许在接口中定义两类新方法:静态方法和默认方法,它们有实现体,比如:
java
public interface IDemo {
void hello();
public static void test() {
System.out.println("hello");
}
default void hi() {
System.out.println("hi");
}
}
test()就是一个静态方法,可以通过IDemo.test()调用。在接口不能定义静态方法之前,相关的静态方法往往定义在单独的类中,比如,Java API中,Collection接口有一个对应的单独的类Collections,在Java 8中,就可以直接写在接口中了,比如Comparator接口就定义了多个静态方法。
hi()是一个默认方法,用关键字default表示。默认方法与抽象方法都是接口的方法,不同在于,默认方法有默认的实现,实现类可以改变它的实现,也可以不改变。引入默认方法主要是函数式数据处理的需求,是为了便于给接口增加功能。
在没有默认方法之前,Java是很难给接口增加功能的,比如List接口,因为有太多非Java JDK控制的代码实现了该接口,如果给接口增加一个方法,则那些接口的实现就无法在新版Java上运行,必须改写代码,实现新的方法,这显然是无法接受的。函数式数据处理需要给一些接口增加一些新的方法,所以就有了默认方法的概念,接口增加了新方法,而接口现有的实现类也不需要必须实现。看一些例子,List接口增加了sort方法,其定义为:
java
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for(Object e : a) {
i.next();
i.set((E) e);
}
}
Collection接口增加了stream方法,其定义为:
java
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
在Java 8中,静态方法和默认方法都必须是public的,Java 9去除了这个限制,它们都可以是private的,引入private方法主要是为了方便多个静态或默认方法复用代码,比如:
java
public interface IDemoPrivate {
private void common() {
System.out.println("common");
}
default void actionA() {
common();
}
default void actionB() {
common();
}
}
这里,actionA和actionB两个默认方法共享了相同的common()方法的代码。