如何使用成员变量与接口和匿名实现

时间:2013-06-06 06:05:18

标签: java interface anonymous-class

请检查以下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 个答案:

答案 0 :(得分:7)

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

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

来自JLS section 9.3

  

接口主体中的每个字段声明都是隐式的public,static和final。允许为这些字段冗余地指定任何或所有这些修饰符。

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

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

实际上是:

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

我强烈建议你避免在接口中使用变量,除了以获得真正的常量......即便如此,只有在它真正有意义的地方。目前尚不清楚你想要实现的目标,但在界面中声明一个字段并不是IMO的好方法。

答案 1 :(得分:3)

在java中没有像variable-overriding这样的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";

}

答案 2 :(得分:1)

When i access a interface variable directly

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

Accessing getVal() method, showing proper values

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

public String s = "String Implementation";

答案 3 :(得分:1)

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

因此,写作时

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

你宣布一个常数s。 这就是t.meth().s打印Old value

的原因

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