6

I made a class that contains:

  1. static final variable
  2. static initializer block with a System.out.println() statement

If I call the static final variable from another class, the static block does not execute.

As far as I know, the static initializer block executes when the class is loaded in memory.

In this case, what is happening at the memory level?

Is the class not loading in memory? If not, where do other classes get the address of the final static variable?


Case 1: static block does NOT execute

class Test2 {
    static final int a = 20;

    static {
        System.out.println("one");
    }
}

Case 2: static block does execute

class Test2 {
    static final int a;

    static {
        a = 20;
        System.out.println("one");
    }
}

Output

class Test {
    public static void main(String[] args) {
        System.out.println(Test2.a);
    }
}
  • Case 1:

    20
    
  • Case 2:

    one
    20
    

So what is happening at both levels?

Deepak
  • 143
  • 1
  • 13

2 Answers2

12

My guess is that your field is of either a primitive type or String, and is initialized with a compile-time constant expression.

For static final fields initialized with a constant expression (and only such fields) - any code which refers to the field will have the constant value baked into it, rather than going via the static field which would cause class initialization. The "constant expression" part is important though. We can see this with a small test app:

class Fields {
    
    public static final String CONSTANT = "Constant";
    public static final String NON_CONSTANT = new String("Non-constant");
    
    static {
        System.out.println("Initializing");
    }
}

public class Test {
    public static void main(String arg[]) {
        System.out.println(Fields.CONSTANT);
        System.out.println(Fields.NON_CONSTANT);
    }
}

The output is:

Constant
Initializing
Non-constant

Accessing the constant field does not require initialization, but accessing the non-constant one does. Using a non-final field would have the same effect: it would no longer count as a constant, basically.

The information about "this is a constant" gets baked into the class declaring a field. For example, using javap -c Fields we see the two fields:

public static final java.lang.String CONSTANT;
  flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
  ConstantValue: String Constant

public static final java.lang.String NON_CONSTANT;
  flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL

Note the ConstantValue part of the CONSTANT field metadata, which is missing from the NON_CONSTANT field metadata.

See section 15.28 of the JLS for more on what constitutes a constant expression.

Section 12.4.1 of the JLS specifies when a class is initialized:

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.

  • T is a class and a static method declared by T is invoked.

  • A static field declared by T is assigned.

  • A static field declared by T is used and the field is not a constant variable (§4.12.4).

  • T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.

(Emphasis mine.)

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Actually I read when first time class name comes inside code. That time class loads in memory. Is this right? if wrong when class loads? – Deepak Sep 25 '13 at 06:57
  • 1
    @deepak: That's wrong, as you've seen - see my edit for details of when a class is initialized. – Jon Skeet Sep 25 '13 at 07:15
  • Bullet 3 of Section 12.4.1 might lead one to believe that `CONSTANT` is _assigned_ the value "Constant" and thus causes class initialization, but the field is instead _initialized_ and thus Bullet 3 does not apply. [This wiki](https://stackoverflow.com/questions/2614072/java-define-terms-initialization-declaration-and-assignment) can help differentiate between field initialization and assignment. –  Apr 16 '18 at 10:56
  • By the way, bullet 5 in the same section has gone rogue. –  Apr 16 '18 at 10:56
  • @Ichiro: Fixed the bullet. I'll leave your comment to speak for itself. – Jon Skeet Apr 16 '18 at 13:57
11
  1. A static final field is a compile-time constant and its value is hardcoded into the destination class without a reference to its origin;

  2. therefore your main class does not trigger the loading of the class containing the field;

  3. therefore the static initializer in that class is not executed.

See the magic removing final from definition. You will see static initialiser executing

Deepak Ingole
  • 14,912
  • 10
  • 47
  • 79
  • 2
    This isn't actually the whole story - it doesn't apply to *all* static final fields, as your first point implies. See my answer for more details. – Jon Skeet Sep 25 '13 at 06:12