8

Java 8 引入了默认方法的概念。考虑以下带有默认方法的接口:

public interface IDefaultMethod {

    public abstract void musImplementThisMethod();
    public default void mayOrMayNotImplementThisMethod() {
        System.out.println(" This method is optional for classes that implement this interface ");
    }

}

还有一个实现这个接口的类:

    public class DefaultMethodImpl implements IDefaultMethod {

        @Override
        public void musImplementThisMethod() {
                System.out.println("This method must be implementd ");
        }


        @Override
        public void mayOrMayNotImplementThisMethod() {
            // TODO Auto-generated method stub
            IDefaultMethod.super.mayOrMayNotImplementThisMethod();
        }

}

我对以下调用的可读性有疑问mayOrMayNotImplementThisMethod

IDefaultMethod.super.mayOrMayNotImplementThisMethod();

我了解在上述调用中显式指定接口名称的原因是为了避免在类实现的多个接口具有相同方法的情况下产生混淆。我不明白的是super关键字在这种情况下的含义。当我们说 时IDefaultMethod.super,我们到底指的是什么?IDefaultMethod.mayOrMayNotImplementThisMethod() 不是比 IDefaultMethod.super.mayOrMayNotImplementThisMethod() 更具可读性吗?删除 super 关键字使其更具可读性,但代价是区分静态或非静态方法调用。

4

4 回答 4

7

我将尝试按照我自己的推理为讨论做出贡献。

使用类

首先,让我们看看它是如何与简单的 Java 类一起工作的:

class Barney {
    void foo() { System.out.println("Barney says foo"); }
}

class Fred extends Barney {
    @Override void foo() { super.foo(); }
}

foo在这种情况下,如果我们在实例中调用该方法,Fred它将要求在其超类中实现该foo方法并执行该方法。

显然,这些其他方法都不起作用:

@Override void foo() { foo(); } //means this.foo() so infinite recursion
@Override void foo() { Barney.foo(); } //means a static method

我们可以做第三种配置:

class Barney {

    void foo() { System.out.println("Barney says foo"); }

    class Fred extends Barney {
        @Override void foo() { Barney.this.foo(); }
    }

}

在这种情况下,如果我们foo在 的实例中调用Fred,因为该实例将与其封闭实例有联系,因此该调用将调用 的foo封闭实例中的方法Barney

例如

new Barney().new Fred().foo();

因此,Barney.this此处的使用用于在内部/外部关系中的实例之间导航。

使用接口

现在让我们尝试用接口重复相同的想法。

interface Barney {
    default void foo() { System.out.println("Barney says foo"); }
}


interface Fred extends Barney {
    @Override default void foo() { Barney.super.foo(); }
}

据我所知,这与类完全相同,只是在这种情况下,由于接口可以从多个接口继承,我们只需super使用我们在此中定位的接口的名称来限定关键字案子。

意思是一样的,我们要foo在显式命名的超接口中调用方法的“实现”。

与类一样,以下内容不起作用:

@Override default void foo() { super.foo(); } //can't be sure of which interface
@Override default void foo() { this.foo(); } //infinite recursion
@Override default void foo() { Barney.foo(); } //static method
@Override default void foo() { Barney.this.foo(); } //not an inner class relation

所以,这里的逻辑选择是Interface.super.method()

这里的一个问题是我们是否曾经有过Interface.this.method使用接口时的用例。

并非如此,因为接口代表一个静态上下文,因此接口之间从来没有像内部类这样的概念。所以这是永远不可能的。

interface Barney {
    default void foo() { System.out.println("Barney says foo"); }

    interface Fred extends Barney {
            @Override default void foo() { Barney.this.foo(); }
    }
}

基本上,这是不可能的,因为上面的代码并不意味着 的实例Fred需要存在于 的实例的上下文中Barney。这只是一个静态内部接口,它的实例可以独立于父接口的任何实例存在。

所以,这就是为什么这不是一个好的选择。

所以,正如你所看到的,毕竟使用superkind of 是有道理的,或者至少我希望我已经很好地解释了自己以传达这个想法。

于 2015-01-25T15:25:01.540 回答
5

这只是对访问超类成员的常用方法的默认方法的扩展(JLS 15.11)

表单引用对应于 的词法封闭实例T.super.Identifier命名的字段,但该实例被视为 的超类的实例。IdentifierTT

从本质上讲,当一个类有多个祖先时(无论是因为默认方法还是仅仅因为它在层次结构中有多个超类),关于哪个成员被引用可能会产生歧义。关键字是内部类中的super类似物;Outer.this这意味着您想要获得 " this,但是我会在该超类的主体中看到的东西,而不是该子类中的成员"。

于 2015-01-25T14:34:26.293 回答
1

super指您继承的类或接口。这意味着您想调用一个方法而忽略它已被覆盖的事实。

如果您使用过this,您将引用此类(或子类),因此具有无限递归。

于 2015-01-25T14:52:48.513 回答
1

Java 8 接口也有静态方法。

如果你说,IDefaultMethod.mayOrMayNotImplementThisMethod();
那么它是一种调用静态方法的方式,这似乎也是正确的,因为它类似于我们如何访问类的静态成员。

对于默认方法,如果不使用“super”,那么他们可能使用了“this”,这没有意义,因为“this”属于我们进行方法调用的类。

我的观点是,您是正确的,因为它没有提供良好的可读性,但似乎符合语言设计。

于 2017-02-19T07:51:46.577 回答