• Java 8 (8) 默认方法


      传统上,Java程序的接口是将相关方法按照预定组合到一起的方式。实现接口的类必须为接口中定义的方法提供一个实现,或者从父类中集成它的实现。但是,一旦类库的设计者需要更新接口,向接口中加入新的方法时候,这种方式就会出现问题。现存的类为了适应新的接口约定也要进行修改。

      Java 8为了解决这个问题,现在接口支持在生命方法的同时提供实现,Java 8 允许在接口内声明静态方法,Java 8 允许在接口中创建默认方法。默认方法可以指定所有实现类的默认实现。这种模式可以让你平滑的进行接口的优化。

    List中的sort方法就是一个静态方法:

        default void sort(Comparator<? super E> c) {
            Object[] a = this.toArray();
            Arrays.sort(a, (Comparator) c);
            ListIterator<E> i = this.listIterator();
            for (Object e : a) {
                i.next();
                i.set((E) e);
            }
        }

    通过default关键字来在接口中定义默认方法。可以直接调用sort,对列表进行排序:

    Arrays.asList(1,2,3,5,54).sort(Comparator.naturalOrder());

    Comparator.naturalOrder是一个静态方法,它返回了一个Comparator对象,按照自然序列对其中的元素进行排序

        public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
            return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
        }

    Collection中的Stream方法也是一个静态方法:

        default Stream<E> stream() {
            return StreamSupport.stream(spliterator(), false);
        }

    Stream是通过StreamSupport调用了一个stream方法,来返回的Stream对象。并且,现在你知道spliterator 是怎么来的了吧,它也是Collection接口的一个默认方法。

    默认方法的引用就是为了解决Java API这样的类库演进问题。因为向接口中增加方法会导致所有实现类受害。它们也都要进行更新。默认方法可以让所有实现类自动继承接口的一个默认实现。

    定义默认方法

      使用default前缀,并加入方法体即可,比如定义一个sized接口:

    public interface Sized {
        int size();
        default boolean isEmpty(){
            return size() == 0;
        }
    }

    所有的实现类,都会自动继承isEmpty的实现。

    Java8中的抽象类和抽象接口

      抽象接口是指函数式接口中 包含的方法->如 Predicate中的test。

        一个类只能继承一个抽象类,但是一个类可以实现多个接口。

      一个抽象类可以设置实例变量,接口不能有实例变量。

    可选方法

      有时,一个类实现了接口,不过却刻意的将一些方法的实现留白。以Iterator接口为例,Iterator接口定义了hasNext、next还有remove方法。Java 8 之前,由于用户通常不会使用该方法,remove方法常被忽略。因此,实现了Iterator接口的类通常会为remove方法放置一个空的实现,这些都是毫无用处的模板代码。

      采用默认方法之后,你可以为这种类型的方法提供一个默认的实现,这样实体类就无需在自己的实现中显示的提供一个空方法。

    interface Iterator<T> { 

    boolean hasNext(); T next(); default void remove() { throw new UnsupportedOperationException(); } }

    通过这种方式,可以减少很多无效的模板代码。无需再实现remove方法。

    行为的多继承

      默认方法之前是无法优雅的实现多继承的,让一个类从多个来源重用代码的能力。因为java的类只能继承单一的类,但是一个类可以实现多个接口。比如ArrayList类的定义:

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    它继承了一个类,实现了4个接口。因此ArrayList实际上是7个类型的直接子类。在某种程度上,我们早就有了多继承。

    由于Java 8中的接口也可以提供实现,类可以从多个接口中继承他们的行为。

    比如你要实现一个接口,有的类需要可以放大缩小,不需要改变形状。有的类需要改变形状 不需要放大缩小。这时可以将 放大缩小放在一个接口中提供一个实现,放大缩小放在一个接口中,然后在需要的类中 各自实现各自的接口。继承各自的默认实现。不要都放在一个接口中。

    解决冲突的规则

      我们知道,一个类只可以继承一个类,但是可以实现多个接口。随着Java 8 带来的默认方法的加入,有可能会出现类或者多个接口中的默认方法出现重复的问题。在这种情况下,

    1.类的方法优先级最高,类或父类中声明的方法的优先级高于任何声明的默认方法的优先级。

    2.如有无法依据第一条进行判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,如果B实现了A,那么A就更具体。

    3.最后,如果还是无法判断,继承了多个接口的类必须通过显示覆盖和调用期望的方法,显示的选择使用哪一个默认方法的实现。

    public class C implements B,A{
        void hello(){
            //显示指定哪个接口中的同名方法
            B.supper.hello();
        }   
    }

    小结

      1.Java 8中的接口可以通过默认方法和静态方法提供代码的实现。

      2.默认方法的开头以关键字default修饰,方法体与常规类的方法相同。

      3.向发布的接口添加抽象方法不是源码兼容的。

      4.默认方法的出现能帮助库的设计者以后向兼容的方式演进API。

      5.默认方法可以用于创建可选方法和行为的多继承。

      6.当函数名重复时,可以按照优先级进行判断,类和父类实现最高,其他无法确定时,可以显示指定调用哪个。

  • 相关阅读:
    RNN-2-前向传播、BPTT反向传播
    RNN-1-参数共享、网络的展开、常见应用
    被围绕的区域
    语言模型的评价方法
    个性化推荐系统
    推荐系统-CTR-Wide&Deep
    推荐系统-CTR-总结
    推荐系统-CTR-PNN
    Local variable flag defined in an enclosing scope must be final or effective
    2.两数相加
  • 原文地址:https://www.cnblogs.com/baidawei/p/9437723.html
Copyright © 2020-2023  润新知