为什么可以覆盖Java中的最终常量?

时间:2008-10-15 15:43:33

标签: java interface override final

考虑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"!!!

6 个答案:

答案 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,因为它更易于显示。