3

The class Integer is a wrapper of the int primitive type (https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html). An object is considered immutable if its state cannot change after it is constructed (https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html).

What I understand here is that you can only change the value of an Integer variable by referencing a completely different Integer object.

By declaring a variable final we can assure the following:

Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.

Yet again, by the immutable documentation:

An object is considered immutable if its state cannot change after it is constructed.

So a final, immutable Integerwould not be allowed to change its value by any means.

If this is correct, why aren't we allowed to declare a public static final Integer variable?

The following code declares a public static final Integer in different ways, and all of them return a compile time error:

import java.util.*;
import java.lang.*;
import java.io.*;

class Ideone
{
    public class Constants {
        public static final String STRING_CONSTANT = "string_constant";
        public static final int INTEGER_CONSTANT = 1; // allowed
        //public static final Integer INTEGER_CONSTANT = 1; // not allowed
        //public static final Integer INTEGER_CONSTANT = new Integer("1"); // not allowed
        //public static final Integer INTEGER_CONSTANT = Integer.valueOf(1); // not allowed
    }
    public static void main (String[] args) throws java.lang.Exception
    {
        System.out.println("STRING_CONSTANT = " + Constants.STRING_CONSTANT);
        System.out.println("INTEGER_CONSTANT = " + Constants.INTEGER_CONSTANT);
    }
}

The exception thrown is:

Main.java:12: error: Illegal static declaration in inner class Ideone.Constants
        public static final Integer INTEGER_CONSTANT = 1;
                                    ^
  modifier 'static' is only allowed in constant variable declarations
1 error

Can anyone clarify why aren't we allowed to declare a public static final Integer, please?

EDIT: I'm interested in knowing why public static final Integer is not allowed while public static final String and public static final int are, not about finding a code that compiles.

Bernat
  • 492
  • 5
  • 13
  • 6
    Your question doesn't point the fact that your want to declare a static instance in an inner class. **The fact that you can declare primitive constant in that inner class does intrigue me !** – AxelH Nov 06 '17 at 12:14
  • 10
    Your class `Constants` is a non-static inner class. It cannot have static members. – khelwood Nov 06 '17 at 12:15
  • Thanks for your comments. In that case, why can we declare a `public static final String` and `public static final int`? – Bernat Nov 06 '17 at 12:16
  • @Bernat `String` and primitive types are "special" – Lothar Nov 06 '17 at 12:18
  • 2
    I would guess that the compiler is inlining the compile-time constants, so you get away with something that wouldn't normally be allowed. An `Integer` can be a run-time constant, but is not a compile-time constant, so it won't work for that. – khelwood Nov 06 '17 at 12:18
  • @khelwood in the answer to your link: "Inner classes may not declare static members, unless they are compile-time constant fields". I understand a final, immutable object is compile-time constant, isn't it? – Bernat Nov 06 '17 at 12:20
  • @Bernat An `Integer` is an _object_ that is created at run-time. It cannot be a compile-time constant. – khelwood Nov 06 '17 at 12:20
  • 1
    This has some precedence here [Why compile time constants are allowed to be made static in non static inner classes?](https://stackoverflow.com/q/37510433/4391450) – AxelH Nov 06 '17 at 12:23
  • @AxelH Good find. – khelwood Nov 06 '17 at 12:23
  • @AxelH I can't because I'd have to start looking through the specification to find a reason. But I learned to stop wondering about things happening differently than expected when working with primitives and `String` because of their different handling from other types (`String` with its constant pool, primitives... well they are primitives and not Objects). – Lothar Nov 06 '17 at 12:24
  • The compiler would need to create initialisation code for `new Integer` and `Integer.valueOf` and that possibility was excluded for non-static inner classes. It is the case of "allowed stupidity" of the compiler, as for strings it _can_ place the string constant in the constant pool. – Joop Eggen Nov 06 '17 at 12:24

5 Answers5

4

The problem isn't the declaration of the constant but the fact that it's declared in an inner class that is not static. Change the declaration of the class to be static and you're good:

public static class Constants {
    public static final String STRING_CONSTANT = "string_constant";
    public static final int INTEGER_CONSTANT = 1; // allowed
    public static final Integer INTEGER_CONSTANT1 = 1;
    public static final Integer INTEGER_CONSTANT2 = new Integer("1");
    public static final Integer INTEGER_CONSTANT3 = Integer.valueOf(1);
}
Lothar
  • 5,323
  • 1
  • 11
  • 27
  • Thanks for your answer. However, I'm not looking for a solution to the code, but for the reason why Integer is not allowed and String/int are. – Bernat Nov 06 '17 at 12:25
3

You can find the reason behind this in the JLS.

8.1.3. Inner Classes and Enclosing Instances

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 (§4.12.4).

Then, we can check the definition of a constant variable :

4.12.4. final Variables

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

This is why you are allowed to declare a primitive or a String constant. But the Integer class and other boxing class are not part of that exception, those are instance like any other class.

Source : Andy Thomas

Inline constant

If we add that with the following :

13.1. The Form of a Binary

A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.

We can see that those constant don't really exist at run time, the references are resolved at compile time.

Code :

final static int INTEGER_CONSTANT = 1;
int value = INTEGER_CONSTANT;

Run time "code" :

int value = 1;
AxelH
  • 14,325
  • 2
  • 25
  • 55
0

Java allows public static final Integer, but not inside not static inner classes. Move the declaration to the class Ideone or make the class Constants static. You can declare public static final fields in inner classes only if the initialitation is considered compiler constant which only works with string and the primative types.

public static final String a = new String("ds"); //will not work

user2818938
  • 21
  • 1
  • 6
0

As per the JLS ,a compile-time constant expression is an expression denoting a value of primitive type or a String. https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28

Innocuous
  • 84
  • 2
  • 8
-1

Look at you definition. It isn’t problem of static final Integer. But inner (nested) class. Inner class are by default property of parent class and do what need to be done. If you wanna to make this functionality visible to others classes make inner class static and your code will work. But if you wanna use some global config class declare it alone not as subclass.

Elfiadorn
  • 31
  • 8