请检查下面的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((=>"字符串实现">
我不明白这个代码是怎么工作的,有人能给我解释一下吗?
接口中声明的s
变量与您在匿名内部类中声明的s
变量完全分离。
接口变量实际上只是被设计为常量——它们不是每个实现所需提供的API的一部分。特别是,它们是隐含的静态和最终的。
来自JLS第9.3节:
接口主体中的每个字段声明都是隐式公共的、静态的和最终的。允许为这些字段冗余地指定任何或所有这些修饰符。
事实上,您已经通过实现实例访问了字段,这是无关紧要的——这段代码:
System.out.println(t.meth().s);
是有效的:
t.meth();
System.out.println(TestInter.s);
我强烈建议您避免在接口中使用变量,除非用于真正的常量。。。即便如此,也只有在真正有意义的地方。目前还不清楚您想要实现什么,但在接口中声明字段并不是一个好的方法。
在java中,没有什么比variable-overriding
更像method overriding
了。为subclass
命名一个新类型,然后当您通过子类引用类型访问时,您将获得"String Implementation"
。
访问权限protected
只意味着我们可以访问子类中的变量,但不能覆盖它。
即使您使用的是普通的class
而不是interface
,这也不会起作用。当您引用使用super
类类型时,您只能从super
类型中获得instance
变量,依此类推。。。。此示例说明了第一种情况:示例:
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";
}
When i access a interface variable directly
你有接口类型的引用,这就是为什么它直接引用接口,你会得到"旧值">
Accessing getVal() method, showing proper values
当您调用方法getVal((时,您指的是该方法的实际实现,这就是调用实际实现的getVal的原因。这意味着当前实例具有以下值:
public String s = "String Implementation";
接口中声明的字段是常量。
因此,在写入时
interface TestInter
{
String s = "Old value";
String getVal();
}
您正在声明一个常量s。这就是为什么t.meth().s
正在打印Old value
t.meth().getVal()
正在打印您的匿名类的字段s
的内容。