文章目录

  • 关于接口
  • 接口的默认方法
  • 接口的静态方法
  • 接口的私有方法
  • 接口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表达式需求,可以使用;