文章目录
- 关于接口
- 接口的默认方法
- 接口的静态方法
- 接口的私有方法
- 接口VS抽象类
关于接口
- 接口是抽象类的变体,它的结构和抽象类非常相似,也具有数据成员与抽象方法。接口仅提供了方法协议的封装,为了获取并真正实现接口功能,需要使用类来继承该接口,在继承接口的类当中,通过实现接口中抽象方法来实现接口功能。所以在Java中接口是用于实现多继承的一种机制;
- 接口可以通过关键字
externs
继承其他接口,子接口将继承父接口中所有的常量和抽象方法,子接口的非抽象派生类(继承于接口的普通类)不仅要实现子接口的抽象方法,也要实现父类中访问类型为public
的抽象方法,不允许存在没有被实现的接口方法; - 在JDK 1.8之前,接口中的所有方法都是抽象的,没有一个程序体;接口只可以定义
static final
成员变量; - 由于存在抽象类,Java允许接口名作为引用变量的类型;
接口的默认方法
- Java最初的设计中,接口的方法都是没有实现的、公开的;
- 为什么之前的接口当中不允许存在
static方法或者被实现的方法
?
1、静态方法是不能被子类重写的;
2、接口中是不能有被实现的方法的,否则它就不是接口而是抽象类;
3、一个类要实现接口中的方法,其实就是对接口方法的重写;而要实现静态方法,就必须重写接口中的静态方法,这和第一点产生冲突;
- JDK 1.8之后,推出接口的默认的方法/静态方法(都带实现的),为Lambda表达式提供支持;
- 为什么JDK 1.8之后允许存在被实现的方法/静态方法?
1、因为接口是允许多继承的,这一点弥补了Java当中类只能单继承的不足;
2、在JDK 1.8之前,接口与其实现类之间的耦合度
太高了(tightly coupled),当需要为一个接口添加方法时,所有的实现类都必须随之修改。默认方法解决了这个问题,它可以为接口添加新的方法,而不会破坏已有的接口的实现。这在 lambda 表达式作为 java 8 语言的重要特性而出现之际,为升级旧接口且保持向后兼容(backward compatibility)提供了途径;
代码示例:
---JDK 1.8之前
public interface Animal{
public void move();
}
----JDK 1.8之后
public interface Animal{
public default void move(){
System.out.println("I can move.");
}
}
- 接口的默认方法规则如下:
-------以default关键字标注,其他的定义和普通函数一样;
1、默认方法不能重写Object中的方法;
2、实现类可以继承/重写父接口的默认方法;
3、接口可以继承/重写父接口的默认方法;
4、当父类和父接口都存在(同名同参数)默认方法,子类继承父类的默认方法,这样可以兼容JDK 7及之前的代码;
5、子类实现了2个接口(均有同名参数的默认方法),那么编译失败,必须在子类中重写这个default方法;
代码示例1:
public interface Animal {
public void move();
}
public interface NewAnimal {
public default void move(){
System.out.println("I can move.");
}
//不能重写Object方法
/*public default String toString(){
return "qwe";
}*/
}
public abstract class NewFlyAnimal implements NewAnimal{
@Override
public void move(){
System.out.println("I can move in sky.");
}
}
public interface NewLionAnimal extends NewAnimal{
@Override
public default void move() {
System.out.println("I can move on land.");
}
}
public class NewLion implements NewLionAnimal {
@Override
public void move() {
System.out.println("I can move fast.");
}
public static void main(String[] args) {
new NewLion().move();
//I can move fast.---未删除该类中的move()时
//I can move on land.-----删除了该类中的move()时
//I can move.----删除了父接口中的默认move()时
}
}
代码示例2:
public class NewSwan extends NewFlyAnimal implements NewLandAnimal {
public static void main(String[] args) {
new NewSwan().move();
//I can move in sky.---当父类和父接口中存在同名方法,以父类为主,这样可以兼容JDK 7之前的代码
}
}
代码示例3:
public class Lion implements Animal,NewAnimal {
@Override
public void move() {
NewAnimal.super.move();//----这里你要是去掉super,就会报错,因为他不是静态的方法,加上super关键字,通过它明确调用NewAnimal中的move();
}
public static void main(String[] args) {
new Lion().move();
//I can move.------当实现的2个接口中都含有同名的方法,并且至少有一个是默认方法
//子类必须重写该方法,以免歧义
}
}
接口的静态方法
- Java 8接口的静态方法(带实现的)
----该静态方法属于本接口的,不属于子类/子接口(这一点与默认方法是不一样的)
----子类(子接口)没有继承该静态方法,只能通过所在的接口名来调用;
代码示例:
public interface StaticAnimal{
public static void move(){
System.out.println("I can move");
}
}
public class StaticSwan implements StaticAnimal{
public static void main(String[] args){
StaticAnimal.move();
StaticLandAnimal.move();//error
new StaticSwan().move();//error
}
}
public interface StaticLandAnimal extends StaticAnimal{
//也继承不到StaticAnimal中的move()
}
接口的私有方法
- Java 9接口的私有方法(带实现的)
1、解决了多个默认方法/静态方法的内容重复问题;
2、私有方法属于本接口,只在本接口当中使用,不属于子类/子接口;
3、子类(子接口)没有继承该私有方法,也无法调用;
4、静态私有方法可以被静态/默认方法调用,非静态私有方法被默认方法调用;
代码示例:
public interface PrivateAnimal {
public default void run(){
move();
System.out.println("I can run.");
}
-----默认方法可以调用静态/非静态私有方法
public default void fly(){
move2();
System.out.println("I can fly.");
}
private void move(){
//非静态的私有方法
System.out.println("I can move.");
System.out.println("I am growing.");
}
-----静态方法只能调用静态私有方法
public static void run2(){
move2();
System.out.println("I can run.2");
}
public default void fly2(){
move();
System.out.println("I can fly.2");
}
private static void move2(){
//非静态的私有方法
System.out.println("I can move.2");
System.out.println("I am growing.2");
}
}
-----所有私有方法只能在当前接口中使用
接口VS抽象类
- 相同点:(截止Java 12之前,接口和抽象类的对比)
1、都是抽象的,都不能被实例化,既不能被new;
2、都可以实现方法;
3、都可以不需要继承者实现所有的方法;
- 不同点:(截止Java 12之前,接口和抽象类的对比)
1、抽象类最多只能继承一个,接口可以实现多个;
2、接口的变量默认是public static final
,且必须有初值,子类不能修改;抽象类中的变量默认是default
,子类可以继承修改;
3、接口没有构造方法,抽象类有构造方法;
4、接口没有main(),抽象类可以存在mian();
5、接口有public/default/private
的方法,抽象类有public/private/protected/不写关键字的(default)
的方法;
- 总结:
Java 8/9的接口方法:建议少用,如有Lambda表达式需求,可以使用;