Search code examples
javainheritancestaticabstract-class

Static Variables are null before initializing the object itself


Today I'm running into the following issue:

I have three classes, (superclass) A, (subclass) B and my Main class. Here are some code examples of that structure:

public abstract class A {
    
    public static String testValue;

    public static boolean valueSet() {
        return testValue != null;
    }

}
public class B extends A {
    
    static {
        System.out.println("TEST");
        testValue = "foo";
    }
    
}
public class Main {

    public static void main(String[] args) {
        System.out.println(B.testValue);
        System.out.println(B.valueSet());
        System.out.println(new B());
        System.out.println(B.testValue);
        System.out.println(B.valueSet());
    }

}

I'd expect the following output:

foo
true
foo
true

however, the code outputs this instead:

null
false
foo
true

My final goal is to set testValue to some value in every subclass, and implement the checking function just once in the superclass. It has to be static, because it should just check for compatibility of a String against an Object of type A. Definining the using a method as public static abstract is not possible, as I've already read, and there is no way to abstract values, so I can't use that as well. I want the code to stay as simple as possible, without reimplementing the check for every subclass.

Thanks for any help or tips!


Solution

  • You are not initializing the class B prior to calling new B() (in your code example)!

    First of all, you are somewhat misusing the Java possibility of accesing static variables through subtypes. There is no B.testValue, it is only A.testValue. The compiler in fact replaces this. The same is true for the call to B.valueSet(). It is only A.valueSet().

    So, you write

    System.out.println(B.testValue);
    System.out.println(B.valueSet());
    

    but the compiler replaces it with

    System.out.println(A.testValue);
    System.out.println(A.valueSet());
    

    because static members really belong to the class where they are declared.

    A little change to your code shows that:

    public class B extends A {
        public static String foo = "foo"; // Note the new static variable here.
    
        static {
            System.out.println("TEST");
            testValue = "foo";
        }
    }
    
    public class Main {
    
        public static void main(String[] args) {
            System.out.println(B.foo); // Note the new access here.
            System.out.println(B.testValue);
            System.out.println(B.valueSet());
            System.out.println(new B());
            System.out.println(B.testValue);
            System.out.println(B.valueSet());
        }
    
    }
    

    This now correctly prints

    TEST
    foo
    foo
    true
    B@2a139a55
    foo
    true
    

    because now your class B is initialized first.

    Hint: You should always use the declaring class as the reference when accessing static members.