考虑Java中的以下接口:
public interface I {
public final String KEY = "a";
}
以下课程:
public class A implements I {
public String KEY = "b";
public String getKey() {
return KEY;
}
}
为什么A类可能出现并覆盖接口I的最终常量?
亲自尝试:
A a = new A();
String s = a.getKey(); // returns "b"!!!
答案 0 :(得分:36)
你正在隐藏它,它是“范围”的一个特征。每当你在较小的范围内,你可以重新定义你喜欢的所有变量,外部范围变量将是“阴影”
顺便说一句,如果您愿意,可以再次进行搜索:
public class A implements I {
public String KEY = "b";
public String getKey() {
String KEY = "c";
return KEY;
}
}
现在KEY将返回“c”;
编辑,因为原来在重新阅读时很糟糕。
答案 1 :(得分:18)
答案 2 :(得分:4)
看起来你的类只是隐藏变量,而不是覆盖变量:
public class A implements I {
public String KEY = "B";
public static void main(String args[])
{
A t = new A();
System.out.println(t.KEY);
System.out.println(((I) t).KEY);
}
}
如您所见,这将打印“B”和“A”。您甚至可以分配给它,因为A.KEY变量未定义为final。
A.KEY="C" <-- this compiles.
但是 -
public class C implements I{
public static void main (String args[])
{
C t = new C();
c.KEY="V"; <--- compiler error ! can't assign to final
}
}
答案 3 :(得分:2)
您不应该以这种方式访问常量,而是使用静态引用:
I.KEY //returns "a"
B.KEY //returns "b"
答案 4 :(得分:2)
作为设计考虑因素,
public interface I {
public final String KEY = "a";
}
静态方法总是返回父键。
public class A implements I {
public String KEY = "b";
public String getKey() {
return KEY; // returns "b"
}
public static String getParentKey(){
return KEY; // returns "a"
}
}
就像Jom注意到的那样。使用重新定义的接口成员的静态方法的设计可能是一个严重的问题。通常,尽量避免对常量使用相同的名称。
答案 5 :(得分:1)
静态字段和方法附加到声明它们的类/接口(尽管接口不能声明静态方法,因为它们是完全需要实现的抽象类)。
所以,如果你有一个带有public static(vartype)(varname)的接口, 该字段附加到该接口。
如果你有一个类实现该接口,编译器技巧会将(this。)varname转换为InterfaceName.varname。但是,如果您的类重新定义了varname,则会将一个名为varname的新常量附加到您的类,并且编译器现在知道将(。。)varname转换为NewClass.varname。这同样适用于方法:如果新类没有重新定义方法,则(this。)methodName被翻译成SuperClass.methodName,否则,(this。)methodName被翻译成CurrentClass.methodName。
这就是为什么你会遇到警告“x field / method应该以静态方式访问”的原因。编译器告诉你,虽然它可能会使用这个技巧,但它更喜欢你使用ClassName.method / fieldName,因为它更易于显示。