4. 接口继承
接口也是存在继承关系的。接口继承使用 extends 关键字
public interface Interface2 { String NAME = "我是Interface2中的常量"; void eat2(); void run2(); }
当一个类实现 Interface2 接口,将会实现该接口所继承的所有抽象方法:
public interface Interface1 extends Interface2 { String NAME = "我是Interface1中的常量"; void eat(); void run(); @Override void eat2(); @Override void run2(); }
值得注意的是,一个接口可以继承多个父接口,接口名放在 extends 后面,以逗号分割,例如:
// Interface1.java public interface Interface1 { void abstractMethod1(); } // Interface2.java public interface Interface2 { void abstractMethod2(); } // Interface3.java public interface Interface3 extends Interface1, Interface2 { void abstractMethod3(); }
补充一点,当一个实现类存在 extends 关键字,那么 implements 关键字应该放在其后:
public class MyClass extends SuperClass implements Interface { ... }
5默认方法和静态方法.
从 JDK 1.8 开始,接口中可以定义默认方法和静态方法。与抽象方法不同,实现类可以不实现默认方法和类方法。
5.1 默认方法
5.1.1 声明
我们可以使用 default 关键字,在接口主题中实现带方法体的方法,例如:
public interface Personal { void run(); default void eat() { System.out.println("我是默认的吃方法"); } }
5.1.2 调用和重写
在实现类中,可以不实现默认方法:
public class Pet implements Personal { @Override public void run() { System.out.println("动物可以跑步"); }}
我们也可以在实现类中重写默认方法,重写不需要 default 关键字:
public class Pet implements Personal { @Override public void run() { System.out.println("动物可以跑步"); } // 重写默认方法 @Override public void eat() { // 使用 接口名.super.方法名() 的方式调用接口中默认方法 Personal.super.eat(); System.out.println("动物吃东西"); }}
如果想要在实现类中调用接口的默认方法,可以使用接口名.super. 方法名 () 的方式调用。这里的 接口名.super 就是接口的引用。
5.1.3 使用场景
当一个方法不需要所有实现类都进行实现,可以在接口中声明该方法为默认方法;使用默认方法还有一个好处,当接口新增方法时,将方法设定为默认方法,只在需要实现该方法的类中重写它,而不需要在所有实现类中实现。
5.2 静态方法
5.2.1 声明
使用 static 关键字在接口中声明静态方法,例如:
public interface Personal { void walk(); // 声明静态方法 static void sayHello() { System.out.println("Hello imooc!"); } }
5.2.2 调用
类中的静态方法只能被子类继承而不能被重写,同样在实现类中,静态方法不能被重写。如果想要调用接口中的静态方法,只需使用 接口名.类方法名 的方式即可调用:
public class Pet implements Personal { @Override public void walk() { // 调用接口中的类方法 Personal.sayHello(); System.out.println("动物会走路"); } }
6. 接口和抽象类的区别
接口的方法默认是 public ,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象的方法;
接口中除了 static 、final 变量,不能有其他变量,而抽象类可以;
一个类可以实现多个接口,但只能实现一个抽象类。接口自己本身可以通过 extends 关键字扩展多个接口;
接口方法默认修饰符是 public ,抽象方法可以有 public 、protected 和 default 这些修饰符(抽象方法就是为了被重写所以不能使用 private 关键字修饰!);
抽象类主要解决的是子类每次都会重写父类的方法,父类的不需要写方法体,因为每次子类都会重写父类的方法,所以再类前面加上abstract有个提示作用,证明这个方法将要被重写
接口主要解决Java中单继承的缺陷,从设计层面来讲,接口是对行为的抽象,是一种行为规范,抽象类是对类的抽象,是一种模板设计
7. 多个接口中的重名成员解决方法
7.1 多个接口存在重名默认方法
例如有两个接口 MyInteface1.java 和 Interface2.java,存在相同签名的默认方法:
public interface Interface1 { default void defaultMethod() { System.out.println("我是Interface1接口中的默认方法"); } } public interface Interface2 { default void defaultMethod() { System.out.println("我是Interface2接口中的默认方法"); } }
当实现类实现两个接口时,同名的默认方法将会发生冲突,解决办法是在实现类中重写这个默认方法:
public class MyClass implements Interface1, Interface2 { public void defaultMethod() { System.out.println("我是重写的默认方法"); } }
还有一种情况:实现类所继承的父类中也存在与默认方法的同名方法,此时存在三个同名方法:
// 声明父类,并在父类中也定义同名方法 public class FatherClass { public void defaultMethod() { System.out.println("我是FatherClass中的defaultMethod()方法"); } } // 实现类继承父类,并实现两个接口 public class MyClass extends FatherClass implements Interface1, Interface2 { }
实例化 MyClass 类,调用其 defaultMethod() 方法:
MyClass myClass = new MyClass(); myClass.defaultMethod();
此时编译执行,不会报错:
我是SuperClass中的defaultMethod()方法
实际上,在没有重写的情况下,它执行了实现类的父类 FatherClass 的 defaultMethod() 方法。
7.2 多个接口中存在重名常量
例如有两个接口,存在重名的常量:
public interface Interface1 { final int NUM = 100; } public interface Interface2 { final int NUM = 200; }
此时在实现类中,我们可以使用接口名.常量名的方式分别调用:
public MyClass implements Interface1, Interface2 { System.out.println(Interface1.NUM); System.out.println(Interface2.NUM); }
当实现类将入一个继承关系时:
class SuperClass { static int NUM = 300; } public MyClass extends SuperClass implements Interface1, Interface2 { System.out.println(NUM); }
当父类中的属性或常量与接口中的常量同名时,子类无法分辨同名的 NUM 是哪一个。编译程序将会报错:
MyClass.java:4: 错误: 对NUM的引用不明确 System.out.println(NUM); ^ SuperClass 中的变量 NUM 和 Interface1 中的变量 NUM 都匹配 1 个错误
此时只有在子类中声明 NUM,才可以通过编译:
public MyClass extends SuperClass implements Interface1, Interface2 { int NUM = 3; System.out.println(NUM); }
8. 小结
通过学习,我们知道了 Java 的接口是为了解决其单继承的弊端而产生的
可以使用 interface 关键字来声明一个接口
接口内部不能有具体的方法实现。
可以使用 implements 关键字来实现接口
一个接口可以继承多个父接口,接口名放在 extends 后面,以逗号分割。
从 Java 8 开始,接口中可以定义默认方法和静态方法。