CKi*_*ing 8 java default-method
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 ");
}
}
Run Code Online (Sandbox Code Playgroud)
以及实现此接口的类:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
我对以下调用的可读性有疑问mayOrMayNotImplementThisMethod:
IDefaultMethod.super.mayOrMayNotImplementThisMethod();
Run Code Online (Sandbox Code Playgroud)
我理解在上面的调用中明确指定接口名称的原因是为了避免在类实现的多个接口具有相同方法的情况下混淆.我不明白的是super这个上下文中关键字的含义.当我们说IDefaultMethod.super,我们究竟指的是什么?不会IDefaultMethod.mayOrMayNotImplementThisMethod()比IDefaultMethod.super.mayOrMayNotImplementThisMethod()更具可读性吗?删除super关键字使其更具可读性,代价是区分静态或非静态方法调用.
我将通过遵循我自己的推理来尝试为讨论做出贡献.
首先,让我们看看如何使用简单的Java类:
class Barney {
void foo() { System.out.println("Barney says foo"); }
}
class Fred extends Barney {
@Override void foo() { super.foo(); }
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果我们foo在一个Fred实例中调用该方法,它将在其超类中请求该foo方法的实现并执行该方法.
显然,这些其他人都不会起作用:
@Override void foo() { foo(); } //means this.foo() so infinite recursion
@Override void foo() { Barney.foo(); } //means a static method
Run Code Online (Sandbox Code Playgroud)
我们可以做第三种配置:
class Barney {
void foo() { System.out.println("Barney says foo"); }
class Fred extends Barney {
@Override void foo() { Barney.this.foo(); }
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果我们foo在一个实例中调用Fred,因为这个实例与它的封闭实例有一个绑定,这个调用将调用foo封闭实例中的方法Barney.
例如
new Barney().new Fred().foo();
Run Code Online (Sandbox Code Playgroud)
因此,Barney.this这里的使用用于在内/外关系中的实例之间导航.
现在让我们尝试用接口重复相同的想法.
interface Barney {
default void foo() { System.out.println("Barney says foo"); }
}
interface Fred extends Barney {
@Override default void foo() { Barney.super.foo(); }
}
Run Code Online (Sandbox Code Playgroud)
据我所知,这与类完全相同,只是在这种情况下,由于接口可以从多个接口继承,我们只需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
Run Code Online (Sandbox Code Playgroud)
所以,这里的逻辑选择是Interface.super.method().
这里的一个问题是我们的cab是否有一个像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(); }
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,这是不可能的,因为上面的代码并不意味着一个实例Fred需要存在于一个实例的上下文中Barney.这只是一个静态内部接口,它的实例可以独立于父接口的任何实例而存在.
所以,这就是为什么这不是一个好的选择.
所以,正如你所看到的,在所有这些之后,使用super某种意义是有道理的,或者至少我希望我已经足够好地解释了这个想法.
这只是访问超类成员的常用方法的默认方法的扩展(JLS 15.11):
表单
T.super.Identifier引用Identifier了与词汇封闭实例相对应的字段T,但该实例被视为超类的实例T.
本质上,当一个类具有多个祖先时(无论是因为默认方法还是因为它在层次结构中有多个超类),可能存在关于引用哪个成员的歧义.该super关键字是模拟Outer.this在一个内部类; 这意味着你想得到" this,但我会在那个超类的主体内看到的东西而不是这个子类中的成员".