2

我正在编写代码,其中一个类实现了两个接口,这些接口恰好有两个具有相同名称的抽象方法和两个具有相同标识符的常量:

public class Test implements A,B {

  public void doStuff() {}

  public void make() {}

  public static void main(String[] args) {
    Test t=new Test();
    System.out.println(A.VALUE);
    System.out.println(B.VALUE);
    //System.out.println(Test.VALUE);
    //System.out.println(t.VALUE);
  }

}


interface A {              // implicitly abstract

  int VALUE=11;            // implicitly public static and final

  void doStuff();               // implicitly public and abstract

}


interface B {

  int VALUE=14;

  void make();

  void doStuff();

}

现在,我知道从 Java 7 开始,我不必担心名称冲突,就抽象方法而言(对吗??):我只是提供了一个合适的实现,我很好(所有共享的方法同名),所以我不会遇到类似多重继承的问题或“钻石”(我想这是我在使用 Java 8 时要处理的问题)。

但是,就常量而言,我注意到如果我实现了这两个接口并且不尝试访问 VALUE 字段,编译器不会抱怨。当我取消注释打印语句时,它会抱怨。

如何?这是正常行为吗?只有当我访问这些成员时我才会收到错误?

编辑我的意思是,当我尝试实现接口时,为什么编译器不警告我歧义?

4

5 回答 5

1

我的意思是,当我尝试实现接口时,为什么编译器不警告我歧义?

Java 规范允许您定义从具有相同名称变量的不同接口的继承。因此,在您访问 VALUE 之前没有歧义。然后你尝试使用简单的名称来访问它,编译器无法决定它应该使用哪个变量,只有这种情况是模棱两可的。您可以在 Java 规范 https://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#d5e12665中找到详细信息

引用:

一个接口可以继承多个同名字段。这种情况本身不会导致编译时错误。但是,在接口主体中通过其简单名称引用任何此类字段的任何尝试都将导致编译时错误,因为此类引用是模棱两可的。

于 2015-10-01T08:01:49.480 回答
1

现在,我知道从 Java 7 开始,就抽象方法而言,我不必担心名称冲突(对吗??)

这在 Java 7 中并不是什么新鲜事。由于方法在两个接口中具有相同的签名,因此当您在类中实现该方法时,它会为两个接口实现它。那里没有问题,因为没有歧义。

如何?这是正常行为吗?只有当我访问这些成员时我才会收到错误?

是的,当然这是正常行为;这是根据Java编程语言的规则(这不是Java编译器中的错误)。仅从两个接口继承常量本身不会引起歧义,这就是为什么当您尝试这样做时不会出错的原因。

如果你尝试使用没有限定的常量,那么编译器不知道你的意思是这两者中的哪一个,所以它会给你一个错误。

您必须指定要从哪个接口使用该常量:

interface A {
    int VALUE = 11;
}

interface B {
    int VALUE = 14;
}

public class Example implements A, B {
    public void method() {
        // Use A.VALUE instead of just VALUE
        System.out.println(A.VALUE);
    }
}
于 2015-10-01T07:19:52.233 回答
1

接口中的所有变量都是公共静态的。这就是为什么如果您不继承该接口,您可以从任何地方访问它们。

于 2015-10-01T07:20:49.130 回答
0

在您的示例中

interface A {              
  int VALUE=11;           
  void doStuff();               
}

interface B {
  int VALUE = 14;
  void make();
  void doStuff();
}

接口中定义的变量被视为公共静态最终变量。因此,由于静态变量是类级别的变量,它们在整个类中都可用,并且可以通过类名本身访问。

在上面的示例中,接口 A 和 B 具有公共静态最终 VALUE 变量。而A接口变量赋值为11,B接口赋值为14。

A 和 B 接口的完整实现是类 Test。

这里类Test实现A,B

默认情况下,所有属性和行为都在 Test 类中可用。但在这种情况下,VALUE 变量是静态的,其余方法是实例方法。由于静态变量的范围是类级别的,并且与实例变量和实例方法相比,静态变量的内存分配是不同的。

因此范围不同(在班级级别),因此在此没有钻石问题的机会。代码编译良好,输出分别为 11 12。

于 2015-10-01T08:04:05.447 回答
0

虽然实现接口编译器不知道你将在哪里使用它们,所以它不能发出警告。考虑这种情况。有三个类继承了这些接口......“公共类Test实现A,B”“公共类Test1实现A”“公共类Test2实现B”在这个我们不能从任何接口跳过VALUE变量,因为它在三个班级中是强制性的。如果它在创建接口时出错,那么您可能无法实现这种情况。

于 2015-10-01T07:34:13.250 回答