2

With the introduction of default methods in interfaces in Java 8, multiple inheritance may occur, which are resolved by these rules in case of methods. But these rules are not the same in case of member variables. Consider the following example.

public class MyClass {
    public static void main(String args[]) {
        Hello h = new Hello();
        h.sayHello();
    }
}

interface A{
    String temp = "A";
    default public void print() {
        System.out.println("A");
    }
}

interface B extends A{
    String temp = "B";
}

interface C extends A{
    default public void print() {
        System.out.println("C");
    }
}

class Hello implements B, C {
    public void sayHello() {
        print();
        System.out.println(temp);
    }
}

In the above case, implementation of the print() method is taken from interface C, but for variable "temp", the following error occurs:

/MyClass.java:28: error: reference to temp is ambiguous System.out.println(temp); ^ both variable temp in B and variable temp in A match 1 error

Why is this so?

Sajani
  • 117
  • 8
  • 1
    Exactly, it's wrong. default methods aren't added to apply multiple inheritance, that is, their purpose is not to provide multiple inheritance. Listen and read professional's ideas like Brian Goetz, Joshua Bloch, .... – Soner from The Ottoman Empire Feb 22 '18 at 21:04
  • I understand that default methods are NOT added to apply multiple inheritance. Just wanted to understand, if at all a conflict occurs, why does it gets resolved in a different way for methods and variables? – Sajani Feb 22 '18 at 21:09
  • 1
    https://stackoverflow.com/a/32423092/4990642 – Soner from The Ottoman Empire Feb 22 '18 at 21:11

2 Answers2

2

A.temp and B.temp aren't member fields; they're static fields. From JLS 9.3:

Every field declaration in the body of an interface is implicitly public, static, and final. It is permitted to redundantly specify any or all of these modifiers for such fields.

Your specific error is called out in this section as well:

It is possible for an interface to inherit more than one field with the same name. Such a situation does not in itself cause a compile-time error. However, any attempt within the body of the interface to refer to any such field by its simple name will result in a compile-time error, because such a reference is ambiguous. (Emphasis in source.)

To properly use the fields, you'd have to qualify it with the interface name, e.g. System.out.println(A.temp).

Note that this isn't new with Java 8. The same verbiage exists in the JLS for SE 7 and the JLS for SE 6.

Brian
  • 17,079
  • 6
  • 43
  • 66
2

There are a couple of things here actually. First is that you have a (simplified) definition like:

static class Hello implements B, C { ... }

JLS allows for a class to implement same interface twice, indirectly; that same interface being A.

Then, there is the Oracle tutorial that specifically says that

Methods that are already overridden by other candidates are ignored

that is the reason why you see the print from C (since it has been overridden).

The thing with member variables is a bit more tricky (a bit). First suppose you have this:

interface A {
    String temp = "A";
}


class C implements A {
    void m() {
        System.out.println(temp);
    }
}

This would work without problems, because you have inherited the temp variable. On the other hand if you have this:

interface A {
    Object temp = "A";
}

interface B {
    Object temp = "B";
}

class C implements A, B {
    void m() {
        // System.out.println(this.temp);
    }
}

This will compile also, because the JLS says:

It is possible for an interface to inherit more than one field with the same name. Such a situation does not in itself cause a compile-time error.

The problems will arise when you un-comment that line and actually try to use the variable temp. Since variables can not be overridden, A#temp and B#temp are entirely different things (it's called hiding), so once you try to use it - which one is it? Since these are public and static, you can use one of them by:

System.out.println(B.temp);
Eugene
  • 117,005
  • 15
  • 201
  • 306