JDK8中接口的变化
文字描述
- JDK8中,接口中可以定义
default
方法和static
方法。- 接口中的 default方法
只能
使用接口的实现类对象来调用(default方法属于实例)。 - 接口中的 static方法
只能
使用“接口名.静态方法名”
的方式调用(static方法属于接口)。 - 接口中的静态方法
不会
被子接口继承,
接口中的静态变量会
被子接口继承,
接口中的默认方法会
被子接口继承。 - 实现类
可以重写
接口中的默认方法(IDEA中按ctrl+o重写方法)。如果一个类实现了多个接口,并且这些接口中有相同的默认方法,并且这些接口之间没有继承关系,那么这个实现类必须重写
这个重名的默认方法。能通过特殊的语法在重写的方法中指定要调用哪个接口中的默认方法。
这个特殊的语法是:<接口名>.super.<方法名>([参数])
。 - 和上述的第4条类似。
子接口可以重写
父接口中的默认方法(IDEA中按ctrl+o重写方法)。如果一个接口继承了多个接口,并且这些接口中有相同的默认方法,并且这些接口之间没有继承关系,那么这个接口必须重写
这个重名的默认方法。能通过特殊的语法在重写的方法中指定要调用哪个接口中的默认方法。
这个特殊的语法是:<接口名>.super.<方法名>.([参数])
。 - 自从接口里面可以有静态方法,从此接口中可以写main方法, 可以作为程序的入口,但是一般不这么做。
- 在子接口中能使用默认方法来实现父接口中的抽象方法。这样子接口的实现类中就不需要再实现这个抽象方法了,如果实现类再去实现子接口中的默认方法,那么相当于是 “方法重写”,即重写了子接口中的这个默认方法。
- 如果一个接口中只有一个抽象方法(包括继承来的抽象方法),那么这个接口叫做函数式接口,函数式接口能和Lambda表达式配合使用。
@FunctionalInterface
注解标注在接口上,作用就是告诉编译器该接口中只能有一个抽象方法. 包括继承父接口中的抽象方法和接口本身定义的抽象方法, 总共不能超过1个。 - 没有任何方法的接口通常用于标记使用。
例如用于声明某类的实例可以被序列化的接口java.io.Serializable
。
- 接口中的 default方法
代码演示
- 对应上述的 1、2。
package cn.king.demo01;
/**
* 接口
*/
interface MyInter01 {
// 接口中的 default方法 只能被接口的实现类对象调用
default void fun1() {
System.out.println("接口MyInter01中的default方法被调用");
}
// 接口中的 static方法 只能使用“接口名.静态方法名”的方式调用
static void fun2() {
System.out.println("接口MyInter01中的static方法被调用");
}
}
/**
* 实现类
*/
class MyInter01Impl implements MyInter01 {
}
/**
* 测试
*/
public class Demo01 {
public static void main(String[] args) {
MyInter01Impl myInter01 = new MyInter01Impl();
/*
* 接口中的 default方法 只能被接口的实现类对象调用
*/
// 下句输出:接口MyInter01中的default方法被调用
myInter01.fun1();
/*
* 接口中的 static方法 只能使用“接口名.静态方法名”的方式调用
*/
// 下句输出:接口MyInter01中的static方法被调用
MyInter01.fun2();
/*
* 接口中的 static方法 只能使用“接口名.静态方法名”的方式调用.
*/
// 下句报错。不能用实现类随想来调用接口中的静态方法。
//myInter01.fun2();
}
}
- 对应上述的3。
package cn.king.demo01;
/**
* 接口1
*/
interface MyInter01 {
// 子父接口中同名的静态变量
public static String s1 = "MyInter01中的s1";
// 父接口中独有的静态变量
public static String s100 = "s100";
}
/**
* 接口2
*/
interface MyInter02 extends MyInter01 {
// 子父接口中同名的静态变量
public static String s1 = "MyInter02中的s1";
// 子接口中独有的静态变量
public static String s200 = "s200";
}
/**
* 测试
*/
public class Demo01 {
public static void main(String[] args) {
System.out.println(MyInter01.s1); // MyInter01中的s1
System.out.println(MyInter01.s100); // s100
// 接口的静态变量会被子接口继承
System.out.println(MyInter02.s1); // MyInter02中的s1
System.out.println(MyInter02.s100); // s100
System.out.println(MyInter02.s200); // s200
}
}
package cn.king.demo01;
/**
* 接口1
*/
interface MyInter01 {
default void fun1() {
System.out.println("接口MyInter01的默认方法fun1()");
}
}
/**
* 接口2
*/
interface MyInter02 extends MyInter01 {
default void fun2() {
System.out.println("接口MyInter02的默认方法fun2()");
}
}
/**
* 接口2的实现类
*/
class MyInter02Impl implements MyInter02 {
}
/**
* 测试
*/
public class Demo01 {
public static void main(String[] args) {
// 接口的默认方法会被子接口继承
MyInter02Impl myInter02 = new MyInter02Impl();
myInter02.fun1(); // 接口MyInter01的默认方法fun1()
myInter02.fun2(); // 接口MyInter02的默认方法fun2()
}
}
- 对应上述4。
package cn.king.demo01;
/**
* 接口1
*/
interface MyInter01 {
// 接口MyInter01和接口MyInter02中有同名的default方法fun1()
default void fun1() {
System.out.println("接口MyInter01的默认方法fun1()");
}
}
/**
* 接口2
*/
interface MyInter02 {
// 接口MyInter01和接口MyInter02中有同名的default方法fun1()
default void fun1() {
System.out.println("接口MyInter02的默认方法fun1()");
}
}
/**
* 接口1 和 接口2 的实现类
*/
class MyInterImpl implements MyInter01, MyInter02 {
@Override
public void fun1() {
//MyInter01.super.fun1();
MyInter02.super.fun1();
}
}
/**
* 测试
*/
public class Demo01 {
public static void main(String[] args) {
MyInterImpl myInter = new MyInterImpl();
//myInter.fun1(); // 接口MyInter01的默认方法fun1()
myInter.fun1(); // 接口MyInter02的默认方法fun1()
}
}
- 对应上述的5。
package cn.king.demo01;
/**
* 接口1
*/
interface MyInter01 {
// 接口MyInter01和接口MyInter02中有同名的default方法fun1()
default void fun1() {
System.out.println("接口MyInter01的默认方法fun1()");
}
}
/**
* 接口2
*/
interface MyInter02 {
// 接口MyInter01和接口MyInter02中有同名的default方法fun1()
default void fun1() {
System.out.println("接口MyInter02的默认方法fun1()");
}
}
/**
* 接口1 和 接口2 的子接口
*/
interface MyInter extends MyInter01, MyInter02 {
@Override
default void fun1() {
//MyInter02.super.fun1();
MyInter01.super.fun1();
}
}
/**
* MyInter接口的实现类
*/
class MyInterImpl implements MyInter {
}
/**
* 测试
*/
public class Demo01 {
public static void main(String[] args) {
MyInterImpl myInter = new MyInterImpl();
//myInter.fun1(); // 接口MyInter02的默认方法fun1()
myInter.fun1(); // 接口MyInter01的默认方法fun1()
}
}
- 对应上述的7。
package cn.king.demo01;
/**
* 接口1
*/
interface MyInter01 {
public abstract void fun1();
}
/**
* 接口1的子接口
*/
interface MyInter extends MyInter01 {
// 使用default方法实现了父接口MyInter01中的抽象方法fun1()
@Override
default void fun1() {
System.out.println("MyInter中的default方法fun1()");
}
}
/**
* 接口1的子接口的实现类
*/
class MyInterImpl implements MyInter {
// 重写了接口MyInter中的fun1()方法
@Override
public void fun1() {
System.out.println("MyInterImpl中的方法fun1()");
}
}
jdk8以前接口的特点见我的另一篇博客:抽象类与接口的区别&抽象类中构造方法的作用(super关键词调用父类构造方法的作用)