接口是对动作的抽象,而抽象类是对根源的抽象。比如男人,女人这两个类,那我们可以为这两个类设计一个更高级别的抽象类——人。对于接口,我们可以坐着吃饭,可以站着吃饭,可以用筷子吃饭,可以用叉子吃饭,甚至可以用手抓着吃饭,那么可以把这些吃饭的动作抽象成一个接口——吃饭。所以一个类只能继承一个抽象类,而可以实现多个接口。
接口知识点:
- 接口指定了一组实现类必须要实现的方法,如果不能全部实现,那么必须是abstract class。
- 接口是任何实现该接口的父类,可以将类的实例赋值给接口类型的变量,但是不可以new一个接口的实例。
- 接口可以包含静态方法,所有的方法默认是public abstract的;
- 接口所有变量默认是public static final的(为什么是static的?因为接口指定的是行为,不是状态,在接口中没有实例变量);
- 接口可以包含默认方法,实现类可以继承或者覆盖该默认方法(默认方法是指声明为default的方法,如果没有声明为default,那么子类必须要实现,而default方法如果在子类中没有实现,将采用接口中定义的);
- 实现类必须将接口方法声明为public(如果没有声明为public,默认是default,会报错);
- 类型T的变量不需要转型就能够赋值给类型S的变量,那么这S是T的父类。所以从父类转为子类才需要强制转型;
- 接口中的变量都是static final,所以在子类中不可以重新对其赋值,但是可以直接拿来使用。
继承接口
一个接口可以extends另一个接口,在原本接口的基础上增加额外的方法。
interface Closeable{
void close();
}
interface Channel extends Closeable{
void open();
}
public class Test implements Closeable, Channel{
public void close() { }
public void open() { }
public static void main(String[] args){
Test t = new Test();
t.close();t.open();
Closeable c = (Closeable) t;
c.close(); //实例c无法调用open方法
Channel cc = (Channel) t;
cc.open();
}
}
实现了Channel接口的类必须实现两个方法,而且它的对象可以转成两个接口类型。
静态方法和默认方法
早期的java所有接口方法是没有方法体的,但是现在的接口中可以添加两种有具体实现的方法:静态方法和默认方法。
默认方法
给接口的方法提供默认实现,那么需要给这样的方法加上default修饰符标签。实现了接口的类可以重写覆盖接口中方法的默认实现,也可以直接继承接口中的实现。
默认方法的一个重要用途是接口演化。
public class Bag implements Collection
在java8,Collection接口增加了一个stream方法。如果stream方法不是默认方法,那么Bag类将无法编译,因为它必须实现接口的stream方法。给接口添加一个非默认的方法会导致源代码无法兼容。
如果没有重新编译类,只是直接使用包含该类的旧JAR文件。即使缺失方法,类依然会加载,程序依然能构造Bag实例,但是如果Bag的实例调用了stream方法,那么会发生AbstractMethodError异常。
而采用默认方法可以解决这些问题,Bag类可以重新编译,即使没有重新编译,在调用到stream方法是,会执行Collection接口默认的stream方法。
静态方法
静态方法,只能通过接口名调用,不可以通过实现类的类名或者实现类的对象调用。
实现多个接口
如果一个类实现了两个接口,
1. 两个接口定义了同样的static方法,这个类不会产生错误,因为只能通过接口类调用接口中的静态方法;
2. 两个接口定义了同样的default方法。由于default方法在接口中是有具体的实现的,编译器没有办法决定谁该覆盖谁。所以只能在子类中重写解决歧义;或者其中一个接口是默认方法,另一个不是默认方法,这样也一样会冲突;
3. 两个接口定义了同样的public abstract方法。这样是没有冲突的,因为要么在子类实现public的方法,要么不实现,该类作为abstract class。
interface Closeable{
default boolean close(){return true;}
}
interface Channel{
default boolean close(){return false;}
default boolean open(){return false;}
}
public class Test implements Closeable, Channel{
public boolean close() { //open方法没有冲突,所以可以不重写;但是close方法有冲突,必须在子类中重写解决冲突
return Closeable.super.close();
}
}
如果一个类继承了一个类并实现了一个接口中有同样的方法,这种情况下只关心父类的方法,忽视来着接口的默认方法。