50

I have a class, Super:

public class Super {
    public static String foo = "foo";
}

I also have another class, Sub that extends Super:

public class Sub extends Super {
    static {
        foo = "bar";
    }

    public static void main (String[] args) {
        System.out.println(Super.foo);
    }
}

When I run it, it prints out bar.
My third (and last) class is Testing:

public class Testing {
    public static void main (String[] args) {
        System.out.println(Super.foo);
        System.out.println(Sub.foo);
        System.out.println(Super.foo);
    }
}

This prints:

foo
foo
foo

I don't understand why the contents of foo vary depending on what class you're accessing it from. Can anyone explain?

5
  • 2
    What I meant by that statement was that when I access it from Testing it returns something different than when I access it from Sub. Commented Mar 27, 2012 at 21:43
  • @jmgrosen: Ah, with you now. Commented Mar 27, 2012 at 21:46
  • 3
    FWIW, note the important distinction between what you have above and what you'd have if Sub contained public static String foo = "bar"; (whereupon you get "foo", "bar", "foo" as you probably expect). Commented Mar 27, 2012 at 21:48
  • I'm not sure if the behavior of this code is an argument against having static variables that are neither private nor final, or against letting static initializers (even implicitly) mess with other classes' static variables. Probably both. Commented Sep 19, 2017 at 19:32
  • You can do it in Php! php.net/manual/en/language.oop5.late-static-bindings.php They call it "late static binding", Java do not support it for "final" / "private" / "static" variables. Commented Nov 12, 2019 at 18:22

3 Answers 3

44

I don't understand why the contents of foo vary depending on what class you're accessing it from.

Basically it's a matter of type initialization. The value of foo is set to "bar" when Sub is initialized. However, in your Testing class, the reference to Sub.foo is actually compiled into a reference to Super.foo, so it doesn't end up initializing Sub, so foo never becomes "bar".

If you change your Testing code to:

public class Testing {
    public static void main (String[] args) {
        Sub.main(args);
        System.out.println(Super.foo);
        System.out.println(Sub.foo);
        System.out.println(Super.foo);
    }
}

Then it would print out "bar" four times, because the first statement would force Sub to be initialized, which would change the value of foo. It's not a matter of where it's accessed from at all.

Note that this isn't just about class loading - it's about class initialization. Classes can be loaded without being initialized. For example:

public class Testing {
    public static void main (String[] args) {
        System.out.println(Super.foo);
        System.out.println(Sub.class);
        System.out.println(Super.foo);
    }
}

That still prints "foo" twice, showing that Sub isn't initialized - but it's definitely loaded, and the program will fail if you delete the Sub.class file before running it, for example.

Sign up to request clarification or add additional context in comments.

12 Comments

This seems correct, but do you happen to know why Sub.foo is compiled into Super.foo?
@jmgrosen: Yes - because there's only one variable, declared by Super. As maerics says, it's accessible "via" Sub, but that doesn't mean it's a different variable.
is the same case for final members also
@PrashantShilimkar: I'm not sure exactly what you're asking about, to be honest... a final member can only be assigned once anyway.
"Basically it's a matter of type initialization" No really, it's a matter of class loading. Static blocks run when the class is loaded, first instantiation(or calling a static method) being a cause of class being loaded
|
0

It does not matter where you change value of a static variable, it is the same variabile foo, in Sub or Super. It does not matter neither how many new Sub or new Super objects you create and then modify. The change will be seen everywhere, since Super.foo, Sub.foo, obj.foo share the same piece of storage.This works with primitive types also:

class StaticVariable{
        public static void main(String[] args){
            System.out.println("StaticParent.a = " + StaticParent.a);// a = 2
            System.out.println("StaticChild.a = " + StaticChild.a);// a = 2

            StaticParent sp = new StaticParent();
            System.out.println("StaticParent sp = new StaticParent(); sp.a = " + sp.a);// a = 2

            StaticChild sc = new StaticChild();
            System.out.println(sc.a);// a = 5
            System.out.println(sp.a);// a = 5
            System.out.println(StaticParent.a);// a = 5
            System.out.println(StaticChild.a);// a = 5
            sp.increment();//result would be the same if we use StaticParent.increment(); or StaticChild.increment();
            System.out.println(sp.a);// a = 6
            System.out.println(sc.a);// a = 6
            System.out.println(StaticParent.a);// a = 6
            System.out.println(StaticChild.a);// a = 6
            sc.increment();
            System.out.println(sc.a);// a = 7
            System.out.println(sp.a);// a = 7
            System.out.println(StaticParent.a);// a = 7
            System.out.println(StaticChild.a);// a = 7
        }
}
class StaticParent{
        static int a = 2;
        static void increment(){
            a++;
        }
}
class StaticChild extends StaticParent{
         static { a = 5;}
}

You can refer to a static variable/method via object (like sc.a) or via it's class name (like StaticParent.a). It is preferable to use the ClassName.staticVariable to emphasize the static nature of the variable/method and to give the compiler better opportunities for optimization.

Comments

-3

Static members are not inherited in java as they are the properties of class and they are loaded in class area. they had nothing to do with object creation. however only the child classes can access the static members of their parent classes.

1 Comment

This is true (they aren't "inherited" so much as "shared"), guessing it's down-voted because it doesn't answer the question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.