1

I'm running into a problem when I compile my code. When I compile my code foo2.var returns null in class foo and I can't seem to figure out why. Is there something wrong in how I'm doing the static initialization in the foo2 class to cause foo2.var to be null in the foo class?

Any help is appreciated.

public class foo extends bar {
  public final static String blah = foo2.var;
  ...
}

public abstract class bar {
  ...
}

public class foo2 extends bar {
  public final static String var;

  static {
    var = "newstring";
  }
  ...
}

Null pointer error on the foo2.var line in this example.

MacAttack
  • 25
  • 6
  • 3
    What kind of type is "var"? – EdgeCase Nov 20 '13 at 17:46
  • Did you compile `foo2` before running `foo`? – Rohit Jain Nov 20 '13 at 17:51
  • @RohitJain I'm unsure, When the compiler gets to the foo2.var line it returns null, my understanding was that when the foo2 var instance variable was called that it would automatically run the static initialization in the foo2 class – MacAttack Nov 20 '13 at 17:53
  • Check your imports. If foo2 is an imported class at this context it cannot produce NPE! Maybe you shadowed it by something, that may be null. – Seagull Nov 20 '13 at 17:53
  • I would guess that the answer is that "newstring" is assigned to var after foo2.var is assigned to blah. The order of these things is specified in jls. – emory Nov 20 '13 at 17:53
  • @MacAttack static initialisers are called, when ClassLoader loads class. It will be done, before referencing any field! – Seagull Nov 20 '13 at 17:54
  • I didn't get any error. http://ideone.com/e6fvGz – Anirban Nag 'tintinmj' Nov 20 '13 at 18:00
  • @MacAttack As far as I can assume, you have an foo2 field in foo class, or it'a ancestor. Maybe you can post full code? – Seagull Nov 20 '13 at 18:01
  • @Seagull I can't post full code because of work policy sadly :( is it possible that foo2 class is being loaded after foo tries to initialize the blah String. I didn't think static initialization allowed that but I could be wrong. – MacAttack Nov 20 '13 at 18:25
  • I can tell you that this is being compiled by ant if that changes anything – MacAttack Nov 20 '13 at 18:27
  • @MacAttack ok. Look, If it compiles, but gives an NPE, you have an smth but class in foo2. If you can, run it in debugger. JVM initialises all static fields at class load time, and loads a class, when it first referenced. When you say foo2, class is loaded, and all dependent classes too. All initialisers are done. Then, you try to acess static field, and at this point it must be already initialised. Standard guarantee it! – Seagull Nov 20 '13 at 18:34
  • @MacAttack also as answered meriton, it may be cyclic dependency issue. But if your hierarchy is like posted above, it will be no such problem here. – Seagull Nov 20 '13 at 18:41

5 Answers5

3

You have not specified a type for var try public final static String VAR;

and then why not just

public class foo2 extends bar {
  public final static String var = "newstring";
06needhamt
  • 1,555
  • 2
  • 19
  • 38
  • my bad, it does have a type in the compile, just forgot to write that in the example. does that change anything? – MacAttack Nov 20 '13 at 17:49
  • You can of course assume that type was given there, else the compiler error would have been different. – Rohit Jain Nov 20 '13 at 17:52
3

Accessing a static field (whose value is not a compile-time-constant expression) will trigger initialization of the class declaring that field, during which which the static initializers are executed. However, initialization is only guaranteed to have completed by the time the field is read if there is no cyclic dependency among initializers.

For instance, if you run the program

class Bar {
    static final long bar;

    static {
        System.out.println("Assigning bar");
        bar = Foo.foo;
    }
}
class Foo extends Bar {
    static final long foo;

    static {
        System.out.println("Assigning foo");
        foo = 1;
    }
}

public class Test {
    public static void main(String[] args) {
        new Foo();
        System.out.println(Bar.bar);
    }
}

you get the following output:

Assigning bar
Assigning foo
0
1

because to create a new instance of Foo, Foo.class is initialized, which first initializes its super class Bar.class, which reads the field of Foo.class, but Foo.class is already being initialized. The Java Language Specification mandates in section 12.4.2, step 3, that such a recursive initialization completes immediately, i.e. the caller will see the class in a partially initialized state. That is, Foo.foo is unassigned at the time it is read, and therefore still contains the default value of 0. That value is assigned to Bar.bar, completing initialization of Bar.class. Then, initialization of Foo.class is resumed by running the initializer, which sets Foo.foo to 1.

Practically speaking, you might wish to review the dependencies of your classes and structure your program such that there are no cyclic dependencies among initializers.

meriton
  • 68,356
  • 14
  • 108
  • 175
  • So in your example, how would you change it so that foo was assigned a value first before bar tried to access it? – MacAttack Nov 20 '13 at 20:38
  • Cyclic dependency was exactly the problem and I found a way around by switching up the design of the classes/instance variables connecting to my example. Thanks! – MacAttack Nov 20 '13 at 20:59
2

var doesn't have a type. Also constants in Java are uppercase by convention. Make it:

public class Foo2 {
  public final static String VAR;

  static {
    VAR = "newstring";
  }
  ...
}
t0mppa
  • 3,983
  • 5
  • 37
  • 48
  • my bad, it does have a type in the compile, just forgot to write that in the example. does that change anything? – MacAttack Nov 20 '13 at 17:48
  • Constants don't have to be in uppercase, but that is standard convention. – Templar Nov 20 '13 at 17:49
  • You can of course assume that type was given there, else the compiler error would have been different. – Rohit Jain Nov 20 '13 at 17:51
  • @RohitJain: Granted, but don't see anything else wrong with the code shown in the question. Meaning perhaps we should ask more details. :) – t0mppa Nov 20 '13 at 17:56
0

You are missing a type for var, change that line to the following:

public final static String VAR;
cmd
  • 11,622
  • 7
  • 51
  • 61
0

Specify var type.

Also, by coding convention class names should be written in CamelCase and constants, UNDERSCORED_CAPS

public class Foo2 {
   public final static VAR = "newstring"; // why not?
...
}

Also, you may shadow foo2 class by some variable. Check your imports. Because class static field reference cannot produce NPE!

Seagull
  • 13,484
  • 2
  • 33
  • 45