[英]Calling Overridden Default Method from Anonymous Inner Class
Consider this code: 考虑以下代码:
interface A {
default void doA() {
System.out.println("a");
}
}
interface B {
void doB();
}
class Test implements A {
@Override
public void doA() {
// Works
B b = () -> A.super.doA();
b.doB();
// Does not compile
/*
new B() {
public void doB() {
A.super.doA();
}
}.doB();
*/
}
public static void main(String[] args) {
new Test().doA();
}
}
This is contrived, but basically Test::doA()
tries to wrap this
as a B
and have B::doB()
call its super function A.super.doA()
. 这是做作,但基本
Test::doA()
尝试来包装this
为B
,并有B::doB()
调用它的超强功能A.super.doA()
I can call A.super.doA()
in a lambda of type B
just fine. 我可以在类型
B
的lambda中调用A.super.doA()
很好。 But I cannot figure out the syntax of calling A.super.doA()
inside an anonymous B
. 但是我无法弄清楚在匿名
B
中调用A.super.doA()
的语法。 See the commented out code. 请参阅注释掉的代码。
Any ideas? 有任何想法吗?
Unlike code appearing in anonymous class declarations , the meaning of names and the
this
andsuper
keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).与出现在匿名类声明中的代码不同 ,名称的含义以及出现在lambda正文中的
this
和super
关键字以及引用的声明的可访问性与周围环境相同 (除了lambda参数引入新名称)。The transparency of
this
(both explicit and implicit) in the body of a lambda expression - that is, treating it the same as in the surrounding context - allows more flexibility for implementations, and prevents the meaning of unqualified names in the body from being dependent on overload resolution.的透明度
this
在一个lambda表达式的主体(显式和隐) -即,将它与在周围的上下文-允许实现更大的灵活性,并防止不合格的名称在体内从依赖的含义在超载解决方案上。
Practically speaking, it is unusual for a lambda expression to need to talk about itself (either to call itself recursively or to invoke its other methods), while it is more common to want to use names to refer to things in the enclosing class that would otherwise be shadowed (this, toString()).实际上,lambda表达式需要谈论自己(以递归方式调用其自身或调用其其他方法)是不寻常的,而更常见的情况是希望使用名称来引用封闭类中的内容,否则将被遮盖(这是toString())。 If it is necessary for a lambda expression to refer to itself (as if via
this
), a method reference or an anonymous inner class should be used instead.如果有必要让lambda表达式引用自身(如通过
this
),则应改用方法引用或匿名内部类。
The keyword
this
may be used in a lambda expression only if it is allowed in the context in which the lambda expression appears.仅当在lambda表达式出现的上下文中允许使用关键字
this
才能在lambda表达式中使用该关键字。 Otherwise, a compile-time error occurs.否则,将发生编译时错误。
I think it also can be applied to the keyword super
. 我认为它也可以应用于关键字
super
。
The statement A.super.doA();
语句
A.super.doA();
would be working in the enclosing context (the body of the method Test#doA
), so it is allowed in lambdas as well. 将在封闭上下文(方法
Test#doA
的主体)中工作,因此也可以在lambda中使用它。
class Test implements A {
@Override
public void doA() {
B b = () -> {
System.out.println(super.getClass());
System.out.println(Arrays.toString(super.getClass().getInterfaces()));
};
b.doB();
// ...
}
}
This snippet prints 此摘要打印
class Test
[interface A]
We will compare it with the anonymous class result. 我们将其与匿名类结果进行比较。
class Test implements A {
@Override
public void doA() {
// ...
new B() {
public void doB() {
System.out.println(super.getClass());
System.out.println(Arrays.toString(super.getClass().getInterfaces()));
}
}.doB();
}
}
The snippet outputs 片段输出
class Test$1
[interface B]
Keeping in mind that an anonymous class has own this
and super
and it does not inherit A
(and can't do it), it becomes clear that A.super.doA();
请记住,匿名类拥有
this
和super
并且它不继承A
(并且不能继承),因此很明显, A.super.doA();
can't be compiled in its context. 无法在其上下文中进行编译。
A workaround could be remembering the enclosing context by a lambda, and invoking that lambda in the method of an anonymous class: 一种解决方法是记住lambda所包含的上下文,并通过匿名类的方法调用该lambda:
class Test implements A {
@Override
public void doA() {
Runnable doA = () -> A.super.doA();
new B() {
public void doB() {
doA.run();
}
}.doB();
}
}
If B
inherited A
, it would be possible to call doA()
or B.super.doA()
referring to the default method: 如果
B
继承A
,这将是可以调用doA()
或B.super.doA()
指的是默认方法:
class Test implements A {
@Override
public void doA() {
new B() {
public void doB() {
doA(); // or B.super.doA();
}
}.doB();
}
}
As said in this answer , this is possible in lambda expressions due to the different meaning of this
and super
(compared to inner classes). 就像在这个答案中说的那样,由于
this
和super
(与内部类相比)的含义不同,因此在lambda表达式中是可能的。
The impossibility to do the same with inner classes has been addressed in The Java® Language Specification, §15.12.1 explicitly: Java®语言规范§15.12.1中明确解决了对内部类进行相同操作的可能性 :
The TypeName
.
TypeName
.
super
syntax is overloaded: traditionally, the TypeName refers to a lexically enclosing type declaration which is a class, and the target is the superclass of this class, as if the invocation were an unqualifiedsuper
in the lexically enclosing type declaration.super
语法已重载:传统上, TypeName引用的是一个词法包围的类型声明,它是一个类,而目标是此类的超类,就好像调用是词法包围的类型声明中的不合格super
。…
…
To support invocation of default methods in superinterfaces, the TypeName may also refer to a direct superinterface of the current class or interface, and the target is that superinterface.
为了支持超级接口中默认方法的调用, TypeName也可以引用当前类或接口的直接超级接口,并且目标是该超级接口。
…
…
No syntax supports a combination of these forms, that is, invoking a superinterface method of a lexically enclosing type declaration which is a class, as if the invocation were of the form InterfaceName
.
没有语法支持这些形式的组合,即,调用作为类的词汇封装类型声明的超接口方法,就好像调用的形式为InterfaceName一样
.
super
in the lexically enclosing type declaration.词汇表类型声明中的
super
。class Subclass3 implements Superinterface { void foo() { throw new UnsupportedOperationException(); } Runnable tweak = new Runnable() { void run() { Subclass3.Superinterface.super.foo(); // Illegal } }; }
A workaround is to introduce a
private
method in the lexically enclosing type declaration, that performs the interfacesuper
call.一种解决方法是在词法包围的类型声明中引入
private
方法,该方法执行接口super
调用。
I don't think that it is possible. 我认为不可能。
This one : 这个 :
B b = () -> A.super.doA();
or this one : 或这个:
A.super.doA();
are valid as these statements use the A
instance method as context. 这些语句使用
A
实例方法作为上下文是有效的。
From the anonymous class, things are different as you don't have access to the A
instance context. 与匿名类相比,情况有所不同,因为您无权访问
A
实例上下文。 So A
cannot be referenced. 因此,不能引用
A
The method in the anonymous class can reference final
variables of the enclosing method or the instance of the enclosing method (by prefixing classname.this
) but the method cannot behave as if it was executed in the context of an A
instance method : what A.super.doA()
means. 匿名类中的方法可以引用封闭方法或封闭方法实例的
final
变量(通过给classname.this
加上前缀),但是该方法无法像在A
实例方法的上下文中执行那样操作:什么A.super.doA()
意思。
I think that a section of the JLS has to specified this point. 我认为JLS的一部分必须指定这一点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.