接口的新特性
Java SE7以前:
接口只能有常量和抽象方法,只能通过实现接口来对相关方法进行操作。
interface 接口名{
全局常量;
抽象方法;
}
Java8:
可以在接口中编写方法实现。支持以下定义:
-
常量
-
抽象方法
-
默认方法
-
静态方法
public interface A { String a="a"; /**正常定义一个抽象方法*/ public void method(); /**使用default 来申明一个默认实现方法*/ default void method1(){ System.out.println("I'm default method in Interface A!"); } /** 使用static 来申明一个静态实现方法*/ static void method2(){ System.out.println("I'm default method in Interface A!"); } }
静态方法的使用
直接用接口名.方法名就可以使用。
默认方法的使用
默认方法在实现类中可以直接使用 :
public class TestDemo1 implements A{
public static void main(String[] args) {
TestDemo1 td = new TestDemo1();
//抽象方法必须实现才能使用
td.method();
//默认方法可以直接使用
td.method1();
//静态方法必须通过接口名.方法名使用
A.method2();
}
@Override
public void method() {
System.out.println("override method of Interface A!");
}
}
如果在某个时候我们往接口添加更多的默认方法,实现类可以不用修改继续使用。
默认方法的最典型用法是逐步为接口提供附加功能,而不破坏实现类。
此外,它们还可以用来为现有的抽象方法提供额外的功能:
interface MobilePhone {
/**
* 获取手机长度(毫米)
*/
Double getLength();
/**
* 对getLength方法进行拓展,返回厘米为单位的长度
*/
default String getLengthInCm() {
return getLength() / 10 + "cm";
}
}
默认方法的多继承
当一个类继承多个接口时如果接口中有同方法标签的方法必须重写,否则会报错。
public interface A {
/**使用default 来申明一个默认实现方法*/
default void method1(){
System.out.println("I'm default method in Interface A!");
}
}
public interface A {
/**使用default 来申明一个默认实现方法*/
default void method1(){
System.out.println("I'm default method in Interface B!");
}
}
public class TestDemo2 implements A,B{
@Override
public void method1() {
System.out.println("我是重写的method1!");
}
}
由于类可以实现多个接口,也可以继承类,当接口或类中有相同函数签名的方法时,这个时候到底使用哪个类或接口的实现呢?这里有三个规则可以进行判断:
- 类中的方法优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。
public interface A {
/**使用default 来申明一个默认实现方法*/
default void method1(){
System.out.println("I'm default method in Interface A!");
}
}
public class C {
/**类C中同方法标签的method1*/
public void method1(){
System.out.println("I'm method1 in Class C!");
}
}
public class TestDemo3 extends C implements A{
public static void main(String[] args) {
TestDemo3 td = new TestDemo3();
td.method1();
}
}
结果:I'm method1 in Class C!
- 如果无法依据第一条进行判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果接口B继承了接口A,那么B就比A更加具体。
public interface A {
/**使用default 来申明一个默认实现方法*/
default void method1(){
System.out.println("I'm default method in Interface A!");
}
}
public interface D extends A{
/**使用default 来申明一个默认实现方法*/
@Override
default void method1(){
System.out.println("I'm default method in Interface D!");
}
}
/**TestDemo4实现接口A和D,接口D继承了接口A*/
public class TestDemo4 implements A,D{
public static void main(String[] args) {
TestDemo4 td = new TestDemo4();
td.method1();
}
}
结果:I'm default method in Interface D!
- 最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法,显式地选择使用哪一个默认方法的实现。不然编译都会报错。 (其实就是最开始说的接口默认方法的多继承)
public class TestDemo5 implements A,B{
public static void main(String[] args) {
TestDemo5 td = new TestDemo5();
td.method1();
}
@Override
public void method1() {
A.super.method1();
//B.super.method1();
}
}
结果:I'm default method in Interface A!
java 9
接口支持以下定义:
- 常量
- 抽象方法
- 默认方法
- 静态方法
- 私有方法
- 私有静态方法
public interface JavaNine{
String TYPE_NAME = "java seven interface";
int TYPE_AGE = 20;
String TYPE_DES = "java seven interface description";
default void method01(){
}
default void method02(String message){
}
private void method(){
//在这里,我们将冗余代码提取到通用的私有方法中,以便我们的API客户端无法看到它们。
}
// 其他抽象方法
void method03();
void method04(String arg);
...
String method05();
}
在Interface中编写私有方法时,我们应该遵循以下规则:
- 我们应该使用私有修饰符(private)来定义这些方法。
- 我们不能同时使用私有修饰符(private)和abstract来定义这些方法。
- “私有”方法意味着完全实现的方法,因为子类不能继承并覆盖此方法。
- “抽象”方法意味着无实现方法。这里子类应该继承并覆盖此方法。
- 私有方法必须包含方法体,必须是具体方法。
- 这些接口私有方法仅在该接口内是有用的或可访问的。我们无法从接口访问或继承私有方法到另一个接口或类。