views:

1463

answers:

5

Consider the following interface in Java:

public interface I {
    public final String KEY = "a";
}

And the following class:

public class A implements I {
    public String KEY = "b";

    public String getKey() {
        return KEY;
    }
}

Why is it possible for class A to come along and override interface I's final constant?

Try for yourself:

A a = new A();
String s = a.getKey(); // returns "b"!!!
+25  A: 

You are hiding it, it's a feature of "Scope". Any time you are in a smaller scope, you can redefine all the variables you like and the outer scope variables will be "Shadowed"

By the way, you can scope it again if you like:

public class A implements I {
    public String KEY = "b";

    public String getKey() {
        String KEY = "c";
        return KEY;
    }
}

Now KEY will return "c";

Edited because the original sucked upon re-reading.

Bill K
To expand a bit, you can't override anything but instance methods. Variables and class (static) methods are hidden or shadowed, not overridden.
Keeg
Thanks. I had something about that in my original version, but then realized that he may not have been using "Override" to mean inheritance, he may have just meant "change", so I rephrased it to remove that assumption--but good to have it stated explicitly too.
Bill K
+2  A: 

It looks like your class is simply hiding the variable, not overwriting it:

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);
    }
}

This will print "B", and "A", as you found. You can even assign to it, as the A.KEY variable is not defined as final.

 A.KEY="C" <-- this compiles.

But -

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

    }
}
Steve B.
+1  A: 

Static fields and methods are attached to the class/interface declaring them (though interfaces cannot declare static methods as they are wholly abstract classes which need to be implemented).

So, if you have an interface with a public static (vartype) (varname), that field is attached to that interface.

If you have a class implement that interface, the compiler trick transforms (this.)varname into InterfaceName.varname. But, if your class redefines varname, a new constant named varname is attached to your class, and the compiler knows to now translate (this.)varname into NewClass.varname. The same applies for methods: if the new class does not re-define the method, (this.)methodName is translated into SuperClass.methodName, otherwise, (this.)methodName is translated into CurrentClass.methodName.

This is why you will encounter the warning "x field/method should be accessed in a static way". The compiler is telling you that, although it may use the trick, it would prefer that you used ClassName.method/fieldName, because it is more explicit for readability purposes.

MetroidFan2002
+1  A: 

You should not access your constant in this way, use the static reference instead:

I.KEY //returns "a"
B.KEY //returns "b"
Jorn
+9  A: 

Despite the fact that you are shadowing the variable it's quite interesting to know that you can change final fields in java as you can read here.

André
It's also possible to change the values of final fields from JNI code.
Alexander
Interesting, didn't know that...
André