given the interfaces (which are very large and generated out of language definitions):
interface VisitorA {
default void visit(ASTA1 node) {...}
...
default void visit(ASTA2000 node) {...}
}
interface VisitorB extends VisitorA {
default void visit(ASTB1 node) {...}
...
default void visit(ASTB1000 node) {...}
// due to language embedding all visit methods of VisitorA
// must be overwritten
@Override
default void visit(ASTA1 node) {...}
...
@Override
default void visit(ASTA2000 node) {...}
}
interface VisitorC extends VisitorA {
default void visit(ASTC1 node) {...}
...
default void visit(ASTC1000 node) {...}
// due to language embedding all visit methods of VisitorA
// must be overwritten
@Override
default void visit(ASTA1 node) {...}
...
@Override
default void visit(ASTA2000 node) {...}
}
interface VisitorD extends VisitorB, VisitorC {
default void visit(ASTD1 node) {...}
...
default void visit(ASTD1000 node) {...}
// due to language embedding all visit methods of VisitorA,
// VisitorB, and VisitorC must be overwritten
@Override
default void visit(ASTA1 node) {...}
...
@Override
default void visit(ASTA2000 node) {...}
@Override
default void visit(ASTB1 node) {...}
...
@Override
default void visit(ASTB1000 node) {...}
@Override
default void visit(ASTC1 node) {...}
...
@Override
default void visit(ASTC1000 node) {...}
}
Now compiling the interface VisitorA (containing of about 2.000 overloaded methods) needs about 10s. Compiling the interfaces VisitorB and VisitorC needs each about 1.5 min. But when we try to compile the interface VisitorD, the Java 8 compiler needs about 7 minutes!
We already tried around and the following solution helped a little bit:
interface VisitorAPlain {
void visit(ASTA1 node);
...
void visit(ASTA2000 node);
}
interface VisitorA extends VisitorAPlain {
... // has same default methods as VisitorA above
}
interface VisitorBPlain extends VisitorAPlain {
void visit(ASTB1 node);
...
void visit(ASTB1000 node);
}
interface VisitorB extends VisitorBPlain {
... // has same default methods as VisitorB above
}
interface VisitorCPlain extends VisitorAPlain {
void visit(ASTC1 node);
...
void visit(ASTC1000 node);
}
interface VisitorC extends VisitorCPlain {
... // has same default methods as VisitorC above
}
interface VisitorD extends VisitorBPlain, VisitorCPlain {
default void visit(ASTD1 node) {...}
...
default void visit(ASTD1000 node) {...}
// due to language embedding all visit methods of VisitorAPlain,
// VisitorBPlain, and VisitorCPlain must be overwritten
@Override
default void visit(ASTA1 node) {...}
...
default void visit(ASTA2000 node) {...}
@Override
default void visit(ASTB1 node) {...}
...
default void visit(ASTB1000 node) {...}
@Override
default void visit(ASTC1 node) {...}
...
default void visit(ASTC1000 node) {...}
}
And now the compilation time of the visitorD needs only about 2 minutes. But still this is a lot.
extends VisitorBPlain, VisitorCPlain
, then the compilation time of this interface needs about 15s - even though it has about 5.000 default methods. But we need the that VisitorD is compatible to VisitorB and VisitorC (either by direct extension or the indirect one with the intermediate Plain-interfaces) for casting reasons.I also read the answers to the similar question: slow JDK8 compilation but there the problem seemed to be the with generic type inference: "There's a severe performance regression in Java 8 when it comes to overload resolution based on generic target typing."
So this is kind of different, if anybody would have a tip or a good explanation why it is so; I would be very thankful.
Thank you, Michael
So, if the class already has the same method as an Interface, then the default method from the implemented Interface does not take effect. However, if two interfaces implement the same default method, then there is a conflict.
Multiple Defaults With default functions in interfaces, there is a possibility that a class is implementing two interfaces with same default methods. The following code explains how this ambiguity can be resolved. First solution is to create an own method that overrides the default implementation.
A default method cannot override a method from java.
Default methods enable you to add new functionality to existing interfaces and ensure binary compatibility with code written for older versions of those interfaces.
The credit for this answer goes to @Brian Goetz.
I created a dummy test, where once all the visit
methods were overwritten and overloaded, at the other time where the visitX
methods got different names.
And the outcome was more amazing than I thought:
When overloading and overwriting the visit
methods, the compiler needed nearly 30 minutes!
When I renamed the visit
methods uniquely inside one visitor class, the compiler needed only 46 seconds.
Here is the source code for the dummy test: https://drive.google.com/open?id=0B6L6K365bELNUkVYMHZnZ0dGREk
And here are the screenshots for the compile time at my computer:
VisitorN
contains overloaded and overwritten visit
methods.
VisitorG
contains the optimized visitX
methods, which are only overwritten but not overloaded anymore.
Using the "plain" approach with different visitX
methods, then compiling Visitor_S
and VisitorPlain_S
needs only about 22 seconds (being twice as fast as the approach with overloading directly the default visitX
methods).
Visitor_S
has default
methods, but it extends VisitorPlain_S
having no default
methods. VisitorPlain_S
extends other "plain" visitors without default
methods.
But what I do still not understand -- just for my theoretical interest, is the fact with the bridge methods: In https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html bridge methods only occur doe to type erasing, but in the example we had no generics and so type erasing should not play a role at all. - Maybe anybody has a good explanation why it still maters.
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