How scala traits are implemented in Java? [duplicate] - java

I have played around with Scala for a while now, and I know that traits can act as the Scala equivalent of both interfaces and abstract classes. How exactly are traits compiled into Java bytecode?
I found some short explanations that stated traits are compiled exactly like Java interfaces when possible, and interfaces with an additional class otherwise. I still don't understand, however, how Scala achieves class linearization, a feature not available in Java.
Is there a good source explaining how traits compile to Java bytecode?

I'm not an expert, but here is my understanding:
Traits are compiled into an interface and corresponding class.
trait Foo {
def bar = { println("bar!") }
}
becomes the equivalent of...
public interface Foo {
public void bar();
}
public class Foo$class {
public static void bar(Foo self) { println("bar!"); }
}
Which leaves the question: How does the static bar method in Foo$class get called? This magic is done by the compiler in the class that the Foo trait is mixed into.
class Baz extends Foo
becomes something like...
public class Baz implements Foo {
public void bar() { Foo$class.bar(this); }
}
Class linearization just implements the appropriate version of the method (calling the static method in the Xxxx$class class) according to the linearization rules defined in the language specification.

For the sake of discussion, let's look the following Scala example using multiple traits with both abstract and concrete methods:
trait A {
def foo(i: Int) = ???
def abstractBar(i: Int): Int
}
trait B {
def baz(i: Int) = ???
}
class C extends A with B {
override def abstractBar(i: Int) = ???
}
At the moment (i.e. as of Scala 2.11), a single trait is encoded as:
an interface containing abstract declarations for all the trait's methods (both abstract and concrete)
an abstract static class containing static methods for all the trait's concrete methods, taking an extra parameter $this (in older versions of Scala, this class wasn't abstract, but it doesn't make sense to instantiate it)
at every point in the inheritance hierarchy where the trait is mixed in, synthetic forwarder methods for all the concrete methods in the trait that forward to the static methods of the static class
The primary advantage of this encoding is that a trait without concrete members (which is isomorphic to an interface) actually is compiled to an interface.
interface A {
int foo(int i);
int abstractBar(int i);
}
abstract class A$class {
static void $init$(A $this) {}
static int foo(A $this, int i) { return ???; }
}
interface B {
int baz(int i);
}
abstract class B$class {
static void $init$(B $this) {}
static int baz(B $this, int i) { return ???; }
}
class C implements A, B {
public C() {
A$class.$init$(this);
B$class.$init$(this);
}
#Override public int baz(int i) { return B$class.baz(this, i); }
#Override public int foo(int i) { return A$class.foo(this, i); }
#Override public int abstractBar(int i) { return ???; }
}
However, Scala 2.12 requires Java 8, and thus is able to use default methods and static methods in interfaces, and the result looks more like this:
interface A {
static void $init$(A $this) {}
static int foo$(A $this, int i) { return ???; }
default int foo(int i) { return A.foo$(this, i); };
int abstractBar(int i);
}
interface B {
static void $init$(B $this) {}
static int baz$(B $this, int i) { return ???; }
default int baz(int i) { return B.baz$(this, i); }
}
class C implements A, B {
public C() {
A.$init$(this);
B.$init$(this);
}
#Override public int abstractBar(int i) { return ???; }
}
As you can see, the old design with the static methods and forwarders has been retained, they are just folded into the interface. The trait's concrete methods have now been moved into the interface itself as static methods, the forwarder methods aren't synthesized in every class but defined once as default methods, and the static $init$ method (which represents the code in the trait body) has been moved into the interface as well, making the companion static class unnecessary.
It could probably be simplified like this:
interface A {
static void $init$(A $this) {}
default int foo(int i) { return ???; };
int abstractBar(int i);
}
interface B {
static void $init$(B $this) {}
default int baz(int i) { return ???; }
}
class C implements A, B {
public C() {
A.$init$(this);
B.$init$(this);
}
#Override public int abstractBar(int i) { return ???; }
}
I'm not sure why this wasn't done. At first glance, the current encoding might give us a bit of forwards-compatibility: you can use traits compiled with a new compiler with classes compiled by an old compiler, those old classes will simply override the default forwarder methods they inherit from the interface with identical ones. Except, the forwarder methods will try to call the static methods on A$class and B$class which no longer exist, so that hypothetic forwards-compatibility doesn't actually work.

A very good explanation of this is in:
The busy Java developer's guide to Scala: Of traits and behaviors - Traits in the JVM
Quote:
In this case, it [the compiler] drops the method implementations and field declarations defined in the trait into the class that implements the trait

In the context of Scala 12 and Java 8, you can see another explanation in commit 8020cd6:
Better inliner support for 2.12 trait encoding
Some changes to the trait encoding came late in the 2.12 cycle, and the
inliner was not adapted to support it in the best possible way.
In 2.12.0 concrete trait methods are encoded as
interface T {
default int m() { return 1 }
static int m$(T $this) { <invokespecial $this.m()> }
}
class C implements T {
public int m() { return T.m$(this) }
}
If a trait method is selected for inlining, the 2.12.0 inliner would
copy its body into the static super accessor T.m$, and from there into
the mixin forwarder C.m.
This commit special-cases the inliner:
We don't inline into static super accessors and mixin forwarders.
Instead, when inlining an invocation of a mixin forwarder, the inliner also follows through the two forwarders and inlines the trait method body.

Related

How should I restrict usage of methods of predefined class

Suppose I have created StringUtil class by extending String. Now any third party calling StringUtil can use all the methods defined for String class. How can I restrict usage of some methods?
String class is final, and you can't extend a final class in Java. You have to read more about Java core. For example, begin by reading https://www.w3schools.in/java-tutorial/super-final-keywords/
Also, when you want a string utility, you have several options like Apache-Commons-Lang or Spring-Core that makes your code readable and has more functionalities.
In case you have multiple classes such that you want to give each of them access to a group of methods inside StringUtil, you can do the following:
If Class1, for example, needs only methods: f1, f2, f3 then you could create an interface interface1 such that exposes only f1, f2, f3 and Class will receive an object of type interface1 as a param to its constructor. StringUtil implements interface1.
Do the same for other classes so each class will be able to use only what you expose to them.
You should read also on dependency injection.
The interfaces:
interface Interface1 {
void f1();
}
interface Interface2 {
void f2();
void f3();
}
StringUtils class:
class StringUtils implements Interface1, Interface2 {
#Override
public void f1() {
}
#Override
public void f2() {
}
#Override
public void f3() {
}
}
The classes who use StringUtils class:
class A {
private Interface1 interface1; // you can mark it as final if it's permanent.
public A(Interface1 interface1) {
this.interface1 = interface1;
}
}
class B {
private Interface2 interface2; // you can mark it as final if it's permanent.
public B(Interface2 interface2) {
this.interface2 = interface2;
}
}
In such scenarios, however, there may be some workaround like: override the method in the base throw some expectation from it, but it will not be a real solution. My recommendation will be to use composition over inheritance. That means your base should has a relationship with superclasses. For example, a let assume 2 classes A (same as your String class) and B (same as your StringUtil class).
class A {
public int add(int a, int b) {
return a + b;
}
public int square(int a) {
return a * a;
}
}
class B {
A obj;
B(A obj) {
this.obj = obj;
}
public int add(int a, int b) {
return obj.add(a, b);
}
}
Now your class B only expose only one method add which delegates its behavior to class A's add method. Also square is not available on B.

How to implement a method with an unknown number of arguments?

I have 1 interface and 3 class. I would like the class to be able to both implement the interface which need a transform method. This method must exist but there can't be more than one per class. I don't know the number of parameters taken by this class.
Example :
public interface A{
public void transform(Object ... args);
}
public class B implements A{
public void transform(String a){
System.out.println(a);
}
}
public class C implements A{
public void transform(Integer a, Character b){
System.out.println(a+b);
}
}
// super generic case if possible with Objects + primitive
public class D implements A{
public void transform(int a, String b){
System.out.println(a+b);
}
}
This doesn't work. But I hope you got the idea. Is something like this possible in java ? How should I call them in a generic way ? Let's say if I have an other method like :
void callTransf(A a, Object ... objs){
Method m = a.getClass().getMethods()[0];
m.invoke(a, objs)
}
A practicable solution would be to declare the interface as a generic one:
public interface Transformation<S, R> {
R transform(S source);
}
The type parameter S plays the source role; the type parameter R plays the result role.
You now can create source and result classes for each different transformation. An example:
public final class TransformationSourceForA {
// Here you declare whatever fields and methods you need for an A source.
// For example:
int a;
String b;
}
public final class TransformationResultForA {
// Here you declare whatever fields and methods you need for an A result.
}
With that you declare the transformation as following:
public final class TransformationA implements Transformation<TransformationSourceForA, TransformationResultForA> {
#Override
public TransformationResultForA transform(TransformationSourceForA source) { ... }
}
The principle is to delegate the needs for different fields to a class and not to the method's parameter.
You can achieve what you want, with some changes and some help of functional programming...
TL;DR
The main idea is that the transform method doesn't receive any arguments. Instead, it will return an instance of some functional interface.
The implementation of this functional interface will consist of the code that would have been executed by the transform method if it had arguments.
To represent arguments of different types and/or a different number of arguments for each subclass of the A interface, we'll use covariance in the return type of the method transform.
This means that the functional interface will be generic (so that the type of the arguments can be different for each subclass of A), and that there will be subinterfaces that will extend this functional interface, each one accepting a different number of arguments in its single abstract method. This will allow the transform() method's return value to have either 1, 2, 3, ... etc arguments.
To execute the code returned by the transform() method, we'll do:
instanceOfB.transform().execute("hello");
instanceOfC.transform().execute(1, 'a');
instanceOfD.transform().execute(1, "hello");
Finally, in order to be able to execute the code in a generic way, the base functional interface defines a varargs method executeVariadic(Object... args), which will be implemented as a default method by every child functional interface, delegating to its execute method and casting the arguments as needed.
Now the long version...
Let's start by renaming your A interface to something more descriptive. As it defines a method called transform, let's name it Transformer.
Then, let's create a functional interface that will represent the transform method of the Transformer interface. Here it is:
#FunctionalInterface
public interface Transformation {
void executeVariadic(Object... args);
}
This interface just defines one single abstract method (SAM) that receives an Object... varargs argument. It is there so that subinterfaces can override it.
Now, let's create a Transformation1 functional interface that extends the Transformation interface:
#FunctionalInterface
public interface Transformation1<A> extends Transformation {
void execute(A a);
#Override
#SuppressWarnings("unchecked")
default void executeVariadic(Object... args) {
this.execute((A) args[0]);
}
}
This Transformation1<A> functional interface is generic and defines the single abstract method execute, which takes one argument of type A. The executeVariadic method is overriden as a default method that delegates its execution to the execute method, casting the first argument accordingly. This cast generates a warning, but oh, well... we'd better learn to live with it.
Now, let's create an analogous interface with two generic type parameters and an execute method that receives two arguments whose types match the generic type parameters:
#FunctionalInterface
public interface Transformation2<A, B> extends Transformation {
void execute(A a, B b);
#Override
#SuppressWarnings("unchecked")
default void executeVariadic(Object... args) {
this.execute((A) args[0], (B) args[1]);
}
}
The idea is the same: the Transformation2 interface extends the Transformation interface and we override the executeVariadic method so that it is delegated to the execute method, casting the arguments accordingly (and suppressing the annoying warning).
For completeness, let's introduce the Transformation3 interface, which is analogous to the previous TransformationX ones:
#FunctionalInterface
public interface Transformation3<A, B, C> extends Transformation {
void execute(A a, B b, C c);
#Override
#SuppressWarnings("unchecked")
default void executeVariadic(Object... args) {
this.execute((A) args[0], (B) args[1], (C) args[2]);
}
}
Hope the pattern is clear by now. You should create as many TransformationX interfaces as arguments you want to support for the transform method of your Transformer interface (A interface in your question, remember I've renamed it).
So far so good, I know this answer is long, but I needed to define the interfaces above so that they can now be used to put all the pieces together.
Remember your A interface? Let's not only keep its name changed to Transformer, but also the signature of its transform method:
#FunctionalInterface
public interface Transformer {
Transformation transform();
}
So this is your base interface now. The transform method no longer has arguments, but returns a Transformation instead.
Let's see how to implement your B, C and D classes now. But first, allow me to rename them to TransformerB, TransformerC and TransformerD, respectively.
Here's TransformerB:
public class TransformerB implements Transformer {
#Override
public Transformation1<String> transform() {
return a -> System.out.println(a); // or System.out::println
}
}
The important thing here is the use of covariance in the return type of the transform method. And I'm using the Transformation1<String> type, which is a subtype of Transformation and indicates that, for the TransformerB class, the transform method returns a transformation that accepts one argument of type String. As the Transformation1 interface is a SAM type, I'm using a lambda expression to implement it.
Here's how to invoke the code inside the TransformerB.transform method:
TransformerB b = new TransformerB();
b.transform().execute("hello");
b.transform() returns an instance of Transformation1, whose execute method is immediately invoked with the String argument it expects.
Now let's see the implementation of TransformerC:
public class TransformerC implements Transformer {
#Override
public Transformation2<Integer, Character> transform() {
return (a, b) -> System.out.println(a + b);
}
}
Again, covariance in the return type of the transform method allows us to return a concrete Transformation, in this case Transformation2<Integer, Character>.
Usage:
TransformerC c = new TransformerC();
c.transform().execute(1, 'A');
For the TransformerD example, I've used a three-argument transformation:
public class TransformerD implements Transformer {
public Transformation3<Integer, Double, String> transform() {
return (a, b, c) -> System.out.println(a + b + c);
}
}
Usage:
TransformerD d = new TransformerD();
d.transform().execute(12, 2.22, "goodbye");
This is all type-safe, because the generic types can be specified in the TransformationX return type of each concrete transform method implementation. It's not possible to use primitive types, though, because primitive types cannot be used as generic type parameters.
Regarding how to call the transform method in a generic way, it's straightforward:
void callTransf(Transformer a, Object... args) {
a.transform().executeVariadic(args);
}
This is why the executeVariadic method exists. And it's overriden in each TransformationX interface, so that it can be used polymorphically, as in the code above.
Calling the callTransf method is straightforward too:
callTransf(b, "hello");
callTransf(c, 1, 'A');
callTransf(d, 12, 2.22, "goodbye");
What you are asking isn't possible.
If interface method uses Varargs then others must too. So one solution would be to have both classes use this interface. Here is general idea:
public interface A{
public void transform(char ... args);
}
public class B implements A{
public void transform(char ... args){
String s = "";
for(char c : args){
s += c;
}
System.out.println(s);
}
}
public class C implements A{
public void transform(char ... args){
System.out.println(args[0] + args[1]);
}
}
Now when you are calling method in B then you must convert string to char array:
String str = "example";
char[] charArray = str.toCharArray();
When calling method in A you make sure to convert integer to char:
int i = 5;
transform((char)Character.forDigit(i, 10), 'a'); // 10 stands for number radix which is probably 10
This isn't perfect solution but it is working one.
But a bit simpler solution without varargs is using just char array, but again you need to convert inputs to char array.
public interface A{
public void transform(char[]);
}
public class B implements A{
public void transform(char[] args){
String s = "";
for(char c : args){
s += c;
}
System.out.println(s);
}
}
public class C implements A{
public void transform(char[] args){
System.out.println(args[0] + args[1]);
}
}
Anyway you do it, you will end up with a bit complicated code, even if using generics you must remember that 1 method takes 1 parameter and other one 2. I actually think that it would be best to simply make this methods separate.
It's a very old question but I don't see a correct implementation in any of the solution. OP was going the right way and is the correct implementation but needs to be written like this -
public interface A<T>{
public T transform(Object ... args);
}
public class B implements A{
public void transform(Object ... args){
System.out.println((String)args[0]);
}
}
public class C implements A{
public void transform(Object ... args){
Integer a = (Integer)args[0];
Integer b = (Integer)args[1];
System.out.println(a+b);
}
}
public static void main(String [] vals){
//Interface A
A b = new B();
A c = new C();
b.transform("Hello");
c.transform(new Integer(1), 'c');
}
You will see it's importance if you use Spring or other DI framework then all you need to do is
#Inject
#Qualifier("B") // For Implementation class B
A b;
#Inject
#Qualifier("C") // For Implementation class C
A C
I see accepted answer is very convuluted and in the end, it is just directly calling the implementation class -
Ex:TransformerB b = new TransformerB;
b.transform();
What's the point of creating all the interfaces???
this is a very interesting Question.you can use method overloading concept if you know the maximum number of arguments coming.
lets say you know that at max user can give 2 parameters then you can do something like this.
public void implementation(){
System.out.println("method with zero args")
}
public void implementation(String arg1){
System.out.println("method with one args and is:-"+arg1)
}
public void implementation(String arg1,String arg2){
System.out.println("method with two args and are :-"+arg1+" "+arg2)
}
if you dont know the maximum number of args you can implement in multiple ways.
1.create a collection and store them in collection object and pass the object as argument.
List args= new List();
l.add(arg1)
----------
----------
----------
l.add(argn)
now pass this as argument to the function call as
objecReference.implementation(l)
2.using var arg methods.
this is the very easy way to solve this kind of problems from java 1.8.
in implementation
public String implementation(int(change to required datattype)...x){
//here x will act like an array
for(int a:x){//iam assuming int values are coming
System.out.println(a)
}
}
now you can call this function with atleast 0 args like
objecReference.implementation()
objecReference.implementation(10)
objecReference.implementation(10,20)
objecReference.implementation(12,23,34,5,6)
As per your requirement you want to override method from your interface in class B and C , but you cannot do the way you have done that.
One way to do is as :
public interface A<T> {
public void transform(T ... args);
}
public class B implements A<String> {
#Override
public void transform(String... args) {
}
}
public class C implements A<Integer> {
#Override
public void transform(Integer... args) {
}
}
One possible solution could be to use Marker Interfaces. A marker (or tagging) interface is an interface that has no methods or constants inside it. It provides run-time type information about objects.
Here is an example that uses Input interface as transform method parameter. An instance of a class that implements this marker interface can be used as transform method argument.
public interface Input {
}
public interface Transformable {
void transform(Input input);
}
public class InputForA implements Input {
int a;
String b;
public int getA() {
return a;
}
public InputForA setA(int a) {
this.a = a;
return this;
}
public String getB() {
return b;
}
public InputForA setB(String b) {
this.b = b;
return this;
}
}
public class TransformerA implements Transformable {
#Override
public void transform(Input input) {
InputForA inputForA = (InputForA) input;
System.out.println(inputForA.getA() + inputForA.getB());
}
}

How can I get the data fields from subclass not superclass?

I have a super class named TestSuper
public class TestSuper {
int a = 0;
}
and I have 2 sub classes named TestSub and TestSub2 that extend TestSuper
public class TestSub extends TestSuper{
int a=1;
}
public class TestSub2 extends TestSuper{
int a=2;
}
in my main class i created a method that takes in a type TestSuper and returns the a value of it and in the main i display it on the console
public class Main {
public static void main(String[] args){
System.out.println(test(new TestSub())+" "+test(new TestSub2()));
}
public static int test(TestSuper b){
return b.a;
}
}
but the output is "0 0" instead of "1 2", what do I do?
You need to cast the reference so say which one you want.
public static int test(TestSuper b){
return b instanceof TestSub ? ((TestSub) b).a :
b instanceof TestSub2 ? ((TestSub2) b).a :
b.a;
}
If this seems needlessly complicated, it is. You should use polymorphism instead.
public class TestSuper {
int a = 0;
public int getA() { return a; }
}
public class TestSub extends TestSuper {
int a = 1;
public int getA() { return a; }
}
public class TestSub2 extends TestSuper {
int a = 2;
public int getA() { return a; }
}
public static int test(TestSuper b) {
return b.getA();
}
First understand the difference between hiding and overriding: https://docs.oracle.com/javase/tutorial/java/IandI/override.html
Then create a getter method in the base-class which you can override in the subclass.
You can look into the theory behind this, and then do the only reasonable thing -forget about writing such kind of code.
In good OOP you consider your fields to be part of your "secret" internal implementation. You don't use fields of sub classes in the super class context. Period.
You are even very conservative about making a field protected in the superclass and to use that in subclasses.
When you call test method like this:
test(new TestSub())+" "+test(new TestSub2())
You use upcasting. Upcasting seperates interface and implementation for an object. But for seperating interface and implementation and achieving true implementation in polymorphism, you must use polymorphic structures. The instance variables aren't polymorphic. Because of this, actually you call a variable which is in TestSuper class.
Only instance methods are polymorphic.

In java we can derived the class from abstract class in function itself. Can we do for C# also?

In Java we can derive the class from abstract class in function itself.
Can we do the same thing for C#?
public class A {
public final static A d = new A();
protected abstract class M {
public int getValue() {
return 0;
}
}
protected static M[] c = null;
public final static void Foo() {
if (c == null) {
M[] temp = new M[] {
d.new M() {
public int getValue() {
return 1;
}
},
d.new M() {
public int getValue() {
return 2;
}
},
d.new M() {
public int getValue() {
return 3;
}
}
};
c = temp;
}
}
}
No, there's no equivalent of anonymous inner classes in C#.
Typically for single-method abstract classes or interfaces, you'd use a delegate in C# instead, and often use a lambda expression to create instances.
So something similar to your code would be:
public class A
{
public delegate int Int32Func();
private static Int32Func[] functions;
// Note: this is *not* thread safe...
public static void Foo() {
if (functions == null) {
functions = new Int32Func[]
{
() => 1,
() => 2,
() => 3
};
}
}
}
... except that I'd use Func<int> instead of declaring my own delegate type.
Just to add a reference to Jon Skeet's answer. Anonymous Types in C# can only define public readonly properties. See excerpt from the C# Programming guide (found here https://msdn.microsoft.com/en-us/library/bb397696.aspx):
Anonymous types contain one or more public read-only properties. No
other kinds of class members, such as methods or events, are valid.
The expression that is used to initialize a property cannot be null,
an anonymous function, or a pointer type.
So short answer (as Jon has already stated) is anonymous types cannot have methods but you can use anonymous functions or delegates to get the same behavior in most cases.

Implementing two interfaces with two default methods of the same signature in Java 8

Suppose I have two interfaces:
public interface I1
{
default String getGreeting() {
return "Good Morning!";
}
}
public interface I2
{
default String getGreeting() {
return "Good Afternoon!";
}
}
If I want to implement both of them, what implementation will be used?
public class C1 implements I1, I2
{
public static void main(String[] args)
{
System.out.println(new C1().getGreeting());
}
}
This is a compile-time error. You cannot have two implementation from two interfaces.
However, it is correct, if you implement the getGreeting method in C1:
public class C1 implements I1, I2 // this will compile, bacause we have overridden getGreeting()
{
public static void main(String[] args)
{
System.out.println(new C1().getGreeting());
}
#Override public String getGreeting()
{
return "Good Evening!";
}
}
I just want to add that even if the method in I1 is abstract, and default in I2, you cannot implement both of them. So this is also a compile-time error:
public interface I1
{
String getGreeting();
}
public interface I2
{
default String getGreeting() {
return "Good afternoon!";
}
}
public class C1 implements I1, I2 // won't compile
{
public static void main(String[] args)
{
System.out.println(new C1().getGreeting());
}
}
This is not specific to the question. But, I still think that it adds some value to the context. As an addition to #toni77's answer, I would like to add that the default method can be invoked from an implementing class as shown below. In the below code, the default method getGreeting() from interface I1 is invoked from an overridden method:
public interface I1 {
default String getGreeting() {
return "Good Morning!";
}
}
public interface I2 {
default String getGreeting() {
return "Good Night!";
}
}
public class C1 implements I1, I2 {
#Override
public String getGreeting() {
return I1.super.getGreeting();
}
}
If a class implements 2 interfaces both of which have a java-8 default method with the same signature (as in your example) the implementing class is obliged to override the method. The class can still access the default method using I1.super.getGreeting();. It can access either, both or neither. So the following would be a valid implementation of C1
public class C1 implements I1, I2{
public static void main(String[] args)
{
System.out.println(new C1().getGreeting());
}
#Override //class is obliged to override this method
public String getGreeting() {
//can use both default methods
return I1.super.getGreeting()+I2.super.getGreeting();
}
public String useOne() {
//can use the default method within annother method
return "One "+I1.super.getGreeting();
}
public String useTheOther() {
//can use the default method within annother method
return "Two "+I2.super.getGreeting();
}
}
There is a case where this actually works according to the resolution rules. If one of the interfaces extends one of the others.
Using the example from above:
public interface I2 extends I1 {
default String getGreeting() {
return "Good Afternoon!";
}
}
The result would be:
Good Afternoon!
However, I believe this is going to be a big problem. The whole reason for default interfaces is to allow library developers to evolve apis without breaking implementers.
Understandably they don't allow the methods to compile without the inheritance structure via extension because a library developer could potentially hijack behavior.
However, this has the potential to be self defeating. If a class implements two interfaces that are not related from a hierarchical view, but both define the same default method signature, then the class that extends both interfaces will not compile. (as demonstrated above)
It is conceivable that two different library developers could decide to add default methods at different times using common signatures; in fact it is probable that this will happen in libraries that implement similar concepts such as math libraries. If you happen to be the sorry soul implementing both interfaces in the same class you will be broken on update.
I believe the rule is that the class implementing the duplicate default methods 'must' override the implementation.. The following compiles and runs fine...
public class DupeDefaultInterfaceMethods {
interface FirstAbility {
public default boolean doSomething() {
return true;
}
}
interface SecondAbility {
public default boolean doSomething() {
return true;
}
}
class Dupe implements FirstAbility, SecondAbility {
#Override
public boolean doSomething() {
return false;
}
}
public static void main(String[] args) {
DupeDefaultInterfaceMethods ddif = new DupeDefaultInterfaceMethods();
Dupe dupe = ddif.new Dupe();
System.out.println(dupe.doSomething());
}
}
> false
This is the simple way:
public interface Circle{
default String shape() {
return "Circle drawn...";
}
}
public interface Rectangle{
default String shape() {
return "Rectangle drawn...";
}
}
public class Main implements Circle, Rectangle{
#Override
public String shape() {
return Circle.super.shape();// called using InterfaceName.super.methodName
}
}
Output:
Circle drawn...
Default methods in Java 8 can be viewed as a form of multiple inheritance (except that attribute can not be inherited).
The main motivation behind default methods is that if at some point we need to add a method to an existing interface, we can add a method without changing the existing implementation classes. In this way, the interface is still compatible with older versions. This is a cool feature. However, we should remember the motivation of using Default Methods and should keep the separation of interface and implementation.
interface First{
// default method
default void show(){
System.out.println("Default method implementation of First interface.");
} }
interface Second{
// Default method
default void show(){
System.out.println("Default method implementation of Second interface.");
} }
// Implementation class code
public class Example implements First, Second{
// Overriding default show method
public void show(){
First.super.show();
Second.super.show();
}
public static void main(String args[]){
Example e = new Example();
e.show();
} }

Categories

Resources