二、Java8的默认方法和静态接口方法

默认方法

Java SE 7时代为一个已有的类库增加功能是非常困难的。具体的说,接口在发布之后就已经被定型,除非我们能够一次性更新所有该接口的实现,否则向接口添加方法就会破坏现有的接口实现。默认方法(之前被称为虚拟扩展方法或守护方法)的目标即是解决这个问题,使得接口在发布之后仍能被逐步演化。

这里给出一个例子,我们需要在标准集合API中增加针对lambda的方法。例如removeAll方法应该被泛化为接收一个函数式接口Predicate,但这个新的方法应该被放在哪里呢?我们无法直接在Collection接口上新增方法——不然就会破坏现有的Collection实现。我们倒是可以在Collections工具类中增加对应的静态方法,但这样就会把这个方法置于“二等公民”的境地。

简单的说,Java的接口现在可以实现方法了。默认方法带来的好处是可以为接口添加新的默认方法,而不会破坏接口的实现

最简单的例子

让我们看一个最简单的例子:一个接口A,Clazz类实现了接口A。

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}

public class Clazz implements A {
}

代码是可以编译的,即使Clazz类并没有实现foo()方法。在接口A中提供了foo()方法的默认实现。

使用这个例子的客户端代码:

Clazz clazz = new Clazz();
clazz.foo(); // 调用A.foo()

多重继承

如果一个接口中定义了一个默认的方法,而另外的父类中也定义一个同名的方法,那么调动的时候,该选择哪个呢?

  1. 选择父类中的方法。如果父类重点方法提供了默认的实现,则子类中具有相同名字和参数的方法会被忽略。
  2. 接口冲突。如果父类提供了一个默认的方法,子类中也提供了具有相同名称和参数的方法(不管该方法是否是默认的),那么必须通过覆盖该方法来覆盖。

代码示例

public interface vehicle {
   default void print(){
      System.out.println("我是一辆车!");
   }
}

多个默认方法
一个接口有默认方法,考虑这样的情况,一个类实现了多个接口,且这些接口有相同的默认方法,以下实例说明了这种情况的解决方法:

public interface vehicle {
   default void print(){
      System.out.println("我是一辆车!");
   }
}

public interface fourWheeler {
   default void print(){
      System.out.println("我是一辆四轮车!");
   }
}

第一个解决方案是创建自己的默认方法,来覆盖重写接口的默认方法:

public class car implements vehicle, fourWheeler {
   default void print(){
      System.out.println("我是一辆四轮汽车!");
   }
}

第二种解决方案可以使用 super 来调用指定接口的默认方法:

public class car implements vehicle, fourWheeler {
   default void print(){
      vehicle.super.print();
   }
}

静态默认方法

除了默认方法,Java SE 8还在允许在接口中定义静态方法。这使得我们可以从接口直接调用和它相关的辅助方法(Helper method),而不是从其它的类中调用(之前这样的类往往以对应接口的复数命名,例如Collections)。

   public interface MyInterf {

        String m1();

        default String m2() {
            return "Hello default method!";
        }

        static String m3() {
            return "Hello static method in Interface!";
        }

    }

你可能感兴趣的:(java8,静态方法,default,默认方法)