8

请检查下面的 Java 代码:

public class Test
{
  public static void main(String arg[]) throws Throwable
  {
      Test t = new Test();
      System.out.println(t.meth().s);           //OP: Old value
      System.out.println(t.meth().getVal());    //OP: String Implementation
  }
  private TestInter meth()
  {
    return new TestInter()
    {
      public String s = "String Implementation";
      public String getVal()
      {
        return this.s;
      }
    };
  }
}
interface TestInter
{
  String s = "Old value";
  String getVal();
}

如您所见,我已经匿名创建了一个界面。当我直接访问接口变量时,它将显示“旧值”。

t.meth().s => "旧值"

通过 getVal() 方法访问它会返回正确的值,

t.meth().getVal() => "字符串实现"

我不明白这段代码是如何工作的,有人能给我解释一下吗?

4

4 回答 4

7

s接口中声明的变量与您在匿名内部类中声明的变量完全分开。s

接口变量实际上只是设计为常量——它们不是每个实现需要提供的 API 的一部分。特别是,它们是隐含的静态和最终的。

JLS 第 9.3 节

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

您通过实现实例访问该字段的事实是无关紧要的 - 这段代码:

System.out.println(t.meth().s);

有效地:

t.meth();
System.out.println(TestInter.s);

我强烈建议您避免在接口中使用变量,除了真正的常量......即使这样,也只能在真正有意义的地方使用。目前尚不清楚您要实现什么,但在接口中声明一个字段并不是 IMO 前进的好方法。

于 2013-06-06T06:13:32.453 回答
3

没有什么像variable-overridingjava 那样method overriding。为 命名一个新类型,然后通过子类引用类型访问时subclass会得到,。"String Implementation"

访问权限protected仅意味着我们可以访问子类中的变量,而不是可以覆盖它。

即使您使用普通class而不是interface这个也行不通。当您引用使用super类类型时,您只能instance从类型等中获取变量super......这个例子说明了第一种情况: 例子:

public class Tester
{
  public static void main(String arg[]) throws Throwable
  {
      Tester t = new Tester();
      System.out.println(t.meth().s); // it prints "Old value" because your type is TestInter           
  }
  private TestInter meth()
  {
    return new TestInter()
    {
       protected String s = "String Implementation";

    };
  }
}
class TestInter
{
  protected String s = "Old value";

}

这个例子说明了第二种情况:它打印"String Implementation"

 public class Tester
{
  public static void main(String arg[]) throws Throwable
  {
      Tester t = new Tester();
      System.out.println(t.meth().s);           
  }
  private SubTestInter meth()
  {
    return new SubTestInter();
  }
}
class SubTestInter extends TestInter{
       protected String s = "String Implementation";
}
class TestInter
{
  protected String s = "Old value";

}
于 2013-06-06T06:13:04.193 回答
1
When i access a interface variable directly

你有接口类型的引用,这就是为什么它直接引用接口并且你得到“旧值”

Accessing getVal() method, showing proper values

当您调用方法 getVal() 时,您指的是该方法的实际实现,这就是调用实际实现的 getVal 的原因。这意味着当前实例具有以下值:

public String s = "String Implementation";
于 2013-06-06T06:13:28.253 回答
1

接口中声明的字段是常量。

因此,当写

interface TestInter
{
  String s = "Old value";
  String getVal();
}

您正在声明一个常量 s。这就是为什么t.meth().s要打印Old value

t.meth().getVal()正在打印s您的匿名类字段的内容。

于 2013-06-06T06:14:03.137 回答