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()
.
I can call A.super.doA()
in a lambda of type B
just fine. But I cannot figure out the syntax of calling A.super.doA()
inside an anonymous B
. See the commented out code.
Any ideas?
Anonymous classes also have the same restrictions as local classes with respect to their members: You cannot declare static initializers or member interfaces in an anonymous class. An anonymous class can have static members provided that they are constant variables.
No, you cannot override private methods in Java, private methods are non-virtual in Java and access differently than non-private one. Since method overriding can only be done on derived class and private methods are not accessible in a subclass, you just can not override them.
An anonymous inner class can be useful when making an instance of an object with certain “extras” such as overriding methods of a class or interface, without having to actually subclass a class. Tip: Anonymous inner classes are useful in writing implementation classes for listener interfaces in graphics programming.
An anonymous inner class can be useful when making an instance of an object with certain "extras" such as overloading methods of a class or interface, without having to actually subclass a class. In simple words, a class that has no name is known as an anonymous inner class in Java.
As said in this answer, this is possible in lambda expressions due to the different meaning of this
and super
(compared to inner classes).
The impossibility to do the same with inner classes has been addressed in The Java® Language Specification, §15.12.1 explicitly:
The 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.…
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.
…
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
.
super
in the lexically enclosing type declaration.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.
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).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.
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()). If it is necessary for a lambda expression to refer to itself (as if viathis
), a method reference or an anonymous inner class should be used instead.JLS 10 - 15.27.2. Lambda Body
The keyword
this
may be used in a lambda expression only if it is allowed in the context in which the lambda expression appears. Otherwise, a compile-time error occurs.JLS 10 - 15.8.3.
this
I think it also can be applied to the keyword super
.
The statement 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.
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();
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:
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:
class Test implements A {
@Override
public void doA() {
new B() {
public void doB() {
doA(); // or B.super.doA();
}
}.doB();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With