Java 8中使用接口进行多重继承的变量冲突解决规则是什么?

Java 8中使用接口进行多重继承的变量冲突解决规则是什么?,java,java-8,Java,Java 8,在Java8的接口中引入默认方法后,可能会发生多重继承,在使用方法的情况下,这些继承由规则解决。但对于成员变量,这些规则并不相同。考虑下面的例子。 public class MyClass { public static void main(String args[]) { Hello h = new Hello(); h.sayHello(); } } interface A{ String temp = "A"; defaul

在Java8的接口中引入默认方法后,可能会发生多重继承,在使用方法的情况下,这些继承由规则解决。但对于成员变量,这些规则并不相同。考虑下面的例子。

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);
    }
}
在上述情况下,print()方法的实现取自接口C,但对于变量“temp”,出现以下错误:

/java:28:错误:对temp的引用不明确 系统输出打印项次(温度); ^ B中的可变温度和A中的可变温度 1错误


为什么会这样?

A.temp
B.temp
不是成员字段;它们是
静态
字段。发件人:

接口主体中的每个字段声明都是隐式公开、静态和最终的。允许为此类字段冗余指定任何或所有这些修饰符

您的具体错误也在本节中列出:

接口可以继承多个同名字段。这种情况本身不会导致编译时错误。但是,在接口主体中,任何试图通过其简单名称引用任何此类字段的尝试都将导致编译时错误,因为此类引用不明确。(在源代码中强调。)

要正确使用这些字段,必须使用接口名称对其进行限定,例如
System.out.println(A.temp)


注意,这在Java8中并不新鲜。和中也存在同样的措辞。

这里实际上有几件事。首先,您有一个(简化的)定义,如:

static class Hello implements B, C { ... }
JLS
允许类间接实现同一接口两次;同一个接口是
A

然后,有一个特别的例子说

已被其他候选项覆盖的方法将被忽略

这就是您从
C
中看到
打印的原因(因为它已被覆盖)

使用成员变量的事情有点棘手(有点)。首先,假设您有:

interface A {
    String temp = "A";
}


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

interface B {
    Object temp = "B";
}

class C implements A, B {
    void m() {
        // System.out.println(this.temp);
    }
}
这将毫无问题地工作,因为您继承了
temp
变量。另一方面,如果您有:

interface A {
    String temp = "A";
}


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

interface B {
    Object temp = "B";
}

class C implements A, B {
    void m() {
        // System.out.println(this.temp);
    }
}
这也将编译,因为
JLS
说明:

接口可以继承多个同名字段这种情况本身不会导致编译时错误

当您取消注释该行并实际尝试使用变量
temp
时,就会出现问题。由于变量不能被重写,
A#temp
B#temp
是完全不同的东西(称为隐藏),所以一旦您尝试使用它,它是哪一个?由于这些是公共的和静态的,您可以通过以下方式使用其中一个:

System.out.println(B.temp);

没错,这是错误的。添加默认方法不是为了应用多重继承,也就是说,它们的目的不是提供多重继承。聆听并阅读专业人士的想法,如Brian Goetz、Joshua Bloch等。我知道默认方法并不是为了应用多重继承而添加的。我只是想了解,如果发生冲突,为什么方法和变量会以不同的方式解决冲突?