4

Why does this line:

static final Integer intValue = 1;

give a compiler error, while this line declared in the same way:

static final String strValue = "aaa";

does not.

The full code:

public class InnerClass {
    class NestedClass {
        static final String strValue = "aaa";
        static final Integer intValue = 1;
    }
}

Compile time error:

The field intValue cannot be declared static in a non-static inner type, unless initialized with a constant expression

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Please [edit] the post and add the compiler error. – Turing85 Apr 15 '22 at 16:54
  • 1
    Done, added error @Turing85 – Khushal Singh Apr 15 '22 at 16:55
  • 1
    Interestingly it doesn't give an error when it is a primitive `int` – Paul Samsotha Apr 15 '22 at 17:19
  • 1
    It probably has to do with the fact that `Integer` is a class and although you can assign the int literal `1` to an instance of an `Integer` at runtime, it would still result in a wrapper object allocated on the heap, so it's not a constant expression. Changing to `int` should make it work. String literals are interned and they get a constant chunk of memory so those _are_ constant expressions. – Boris B. Apr 15 '22 at 17:20
  • Note that I initially closed the question as a duplicate of [this one](https://stackoverflow.com/questions/37509919/field-cannot-be-declared-static-in-a-non-static-inner-type-unless-initialized-wi), but on deeper reading saw that it really isn't a dupe and actually (to me) is an interesting question. – Hovercraft Full Of Eels Apr 15 '22 at 17:25
  • 1
    Please, mention the JDK version where you see a compilation error. The same code fails using JDK 11 but successfully compiles when JDK 17 is used. – Ilya Lapitan Apr 16 '22 at 04:28

1 Answers1

3

It is implied that you're using an older version of Java (such as 11), as this is not reproducible with either 17 (openjdk version "17.0.2" 2022-01-18) or 18 (openjdk version "18" 2022-03-22). For this answer, I'm using Java 11 ("11.0.14" 2022-01-18 LTS) as the error you describe is reproducible using that version.

Here's a compilation attempt using Java 11:

% cat Test.java 
public class Test {
    class NestedClass {
        static final Integer intValue = 1;
    }
}

% javac -version
javac 11.0.14

% javac Test.java
Test.java:3: error: Illegal static declaration in inner class Test.NestedClass
        static final Integer intValue = 1;
                             ^
  modifier 'static' is only allowed in constant variable declarations
1 error

Why did that fail? The Java Language Spec (again, for Java 11) states that you cannot define an inner class with a static member, unless that member is a constant:

"It is a compile-time error if an inner class declares a member that is explicitly or implicitly static, unless the member is a constant variable"

Why did it work with a String - static final String strValue = "aaa"? Because a String is a constant:

"A String object has a constant (unchanging) value"

What else besides String is a constant? A final primitive:

"A constant variable is a final variable of primitive type or type String that is initialized with a constant expression"

So what happens if you change the type from Integer to int - does that work? Yes, it works fine:

class InnerClass {
    class NestedClass {
        static final int intValue = 1; // no problems in Java 11 using primitive
    }
}

Or you could try a later Java version, such as 17:

% javac -version
javac 17.0.2
% javac Test.java
%

I did not look further into why later versions allow static final Integer, even though later versions of JLS (such as version 18) still contain the same wording which suggests Integer should not work (even though it clearly does).

"A constant variable is a final variable of primitive type or type String that is initialized with a constant expression"

Kaan
  • 5,434
  • 3
  • 19
  • 41