Explicitly Calling a Default Method in Java

Explicitly calling a default method in Java

As per this article you access default method in interface A using

A.super.foo();

This could be used as follows (assuming interfaces A and C both have default methods foo())

public class ChildClass implements A, C {
@Override
public void foo() {
//you could completely override the default implementations
doSomethingElse();
//or manage conflicts between the same method foo() in both A and C
A.super.foo();
}
public void bah() {
A.super.foo(); //original foo() from A accessed
C.super.foo(); //original foo() from C accessed
}
}

A and C can both have .foo() methods and the specific default implementation can be chosen or you can use one (or both) as part of your new foo() method. You can also use the same syntax to access the default versions in other methods in your implementing class.

Formal description of the method invocation syntax can be found in the chapter 15 of the JLS.

Calling a default method from Interface in Main Class

You need a concrete instance to invoke the method on. If you have not yet created a concrete type, you could do so anonymously. Like,

new Pozdrav() {
}.osn();

Outputs

Ja sam osnovni metod

Explicitly calling a default method in java - when the implemented interface uses generics

The default method you defined is helpless as Spring will implement out of the box a method with the same erasure (see CrudRepository.save()).

Here you don't invoke a default method of an interface :

JpaRepository.super.save(invoice); 

you invoke the abstract save() method of CrudRepository.

But it cannot compile as it is abstract.

It could work as in the quoted question if the JpaRepositorysuper class defined a default save() method but that is not the case.

In this case, what would be the best way of achieving this ?

You could create a default method with a distinct name and from it call save() that at runtime will invoke the runtime InvoiceRepository instance :

default Invoice saveInvoice(Invoice invoice) {
// I do sth here
...
return save(invoice);
}

Java =8 call a default method on interface in a static context with instanceof instance?

No. A default method is an instance method and, in this case, dynamic binding will kick in. There's no construct for a client of an overridden method to force the invocation of the super-implementation. This can only be done from the subclass (as you've done it in callDefaultSaySomethingFromInstance)

Your only option is to expose a different method in the subclass, and make that method call the implemented interface's default method:

class StaticsMethodIsNotOverriden2 implements InterfaceWithDefaultMethod {
public static void main(String[] args) {
...
clazz.superSaySomething(1, 2);
}

//a different name/signature needed
public void superSaySomething(int a, int b) {
System.out.println(String.format("Forcing super method call with %d %d", a, b));
//the subclass calls default method
InterfaceWithDefaultMethod.super.saySomething(a, b);

}

@Override
public void saySomething(int a, int b) {
System.out.println(String.format("Overriden method call with %d %d", a, b));
}

...
}

How to explicitly invoke default method simply, without reflection and dynamic Proxy?

If the interface has only one method, or all its methods have default implementations, all you need to do is creating an anonymous implementation that does not implement the method that you wish to call:

(new DefaultTestInterface() {}).method1();

Demo.

Can you call the parent interface's default method from an interface that subclasses that interface?

You can invoke an inherited interface default method using InterfaceName.super. The rules are the same as for other super method invocations: You can invoke the inherited method that you have overridden, but you can’t directly invoke the method which the inherited method might have overridden. E.g.

interface A
{
void foo();
default void toOverride() {
System.out.println("A");
}
}
interface B extends A
{
default void toOverride() {
A.super.toOverride();
System.out.println("B");
}
}
interface C extends B
{
default void toOverride() {
A.super.toOverride();// does not work
B.super.toOverride();
System.out.println("B");
}
}
class D implements B
{
public void toOverride() {

}
public void foo() {
D.this.toOverride();
B.super.toOverride();
A.super.toOverride(); // does not work!
}
}

But if each overriding method invokes its super method you have a chain of invocations. However, keep in mind that we are talking about interfaces. An implementation can always override a default method without invoking super at all.

Calling default method in interface when having conflict with private method

Update: Seems like it's really a bug.

A class or super-class method declaration always takes priority over a default method!

default hello(...) method from the Myinterface allows you to write without errors:

ClassB b = new ClassB();
b.hello();

Until runtime, because at runtime hello(...) method from the ClassA takes the highest priority (but the method is private). Therefore, IllegalAccessError occurs.

If you remove the default hello(...) method from the interface, you get the same illegal access error, but now at compile time.

How to explicitly invoke default method from a dynamic Proxy?

If you use a concrete impl class as lookupClass and caller for the invokeSpecial it should correctly invoke the default implementation of the interface (no hack for private access needed):

Example target = new Example();
...

Class targetClass = target.getClass();
return MethodHandles.lookup()
.in(targetClass)
.unreflectSpecial(method, targetClass)
.bindTo(target)
.invokeWithArguments();

This of course only works if you have a reference to a concrete object implementing the interface.

Edit: this solution will only work if the class in question (Example in the code above), is private accessible from the caller code, e.g. an anonymous inner class.

The current implementation of the MethodHandles/Lookup class will not allow to call invokeSpecial on any class that is not private accessible from the current caller class. There are various work-arounds available, but all of them require the use of reflection to make constructors/methods accessible, which will probably fail in case a SecurityManager is installed.



Related Topics



Leave a reply



Submit