Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java final static declarations in method local classes

When declaring a local inner class inside a method, why is it legal to include final static Strings or ints but not legal to include other objects?

For instance:

class Outer {
void aMethod() {
    class Inner {
        final static String name = "compiles";
        final static int ctr = 10; // compiles
        final static Integer intThree = Integer.valueOf(3); // does not compile!
        final static obj objConst = new Object(); // does not compile!
    }

    Inner inner = new Inner();
}
}

When I compile this, I get the following:

InnerExample.java:6: inner classes cannot have static declarations
        final static Integer outer = Integer.valueOf(3);
                             ^
InnerExample.java:7: inner classes cannot have static declarations
        final static Object objConst = new Object();
                            ^

Why the distinction? Is it because String is immutable? If so, wouldn't Integer.valueOf() also be valid?

like image 748
chris.wood Avatar asked Jun 22 '13 18:06

chris.wood


People also ask

Can static variables be declared inside a local class?

Explanation: No, the static variables can't be declared inside a local class. This is because each time the function is called, all the variables get created again and are destroyed as soon as the function is returned. This would have been possible id the static variable was of function.

Can we declare static variable as final in Java?

Declaring variables only as static can lead to change in their values by one or more instances of a class in which it is declared. Declaring them as static final will help you to create a CONSTANT. Only one copy of variable exists which can't be reinitialize.

Can you declare method local variable as final?

final is the only allowed access modifier for local variables. final local variable is not required to be initialized during declaration. final local variable allows compiler to generate an optimized code. final local variable can be used by anonymous inner class or in anonymous methods.

Can we declare static method as final?

When a static method is overriden in a subclass it can still be accessed via the superclass making the final declaration not very necessary. Declaring a static method final does prevent subclasses from defining a static method with the same signature.


3 Answers

It's because the first two static members are assigned to compile-time constants of primitive type or type String.

From the Java Language Specification, section 8.1.3:

8.1.3. Inner Classes and Enclosing Instances

Inner classes may not declare static members, unless they are constant variables (§4.12.4), or a compile-time error occurs.

And from 4.12.4:

A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.

EDIT:

I found this surprising at first. Thinking about it more, one advantage to this limitation is that there is no need to worry about when static members of inner classes are initialized. You can move an inner class around in its containing class, without concern that the values of its static members will be changed.

like image 188
Andy Thomas Avatar answered Oct 13 '22 06:10

Andy Thomas


More on the previous answer. The value assigned must be provable by the compiler that it is a constant. The Java compiler knows the semantics of the base types (int, float, etc.) and the java.lang.String class, but not other classes. This is can understand the constantness of the first two examples.

The compiler does not understand that Integer.valueOf(3) is also (effectively) a constant (actually not constant, but always the same) value even though a human, that knows how the Integer class works, does know that. The compiler treats this as if it was Integer.valueOf(x) which can change. It would be nice if Java offered an annotation, such as @interface Consistent, that declared the method behavior as stable for any give parameters, such as:

In Integer class: @Consistent public Integer valueOf(int x) {...}

final static Integer intThree = Integer.valueOf(3); // now compiles!

That indicates the method returns either the same or an equal object on each invocation given the same argument values. Since the argument is a constant expression, the compiler can deduce that the result will be the same/equal in all usage and can thus be treated as a constant. In this case Integer returns the same object, but it can return a different (but equal) object for much lager input values (ie. it caches values near 0).

Note that "new" always returns a different object. For new Object() it is always an object not equal to any other object.

like image 28
Barry Feigenbaum Avatar answered Oct 13 '22 07:10

Barry Feigenbaum


Consider the definition of a compile-time constant expression from 15.28:

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

  • Literals of primitive type and literals of type String (§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5)
  • Casts to primitive types and casts to type String (§15.16)
  • The unary operators +, -, ~, and ! (but not ++ or --) (§15.15.3, §15.15.4, §15.15.5, §15.15.6)
  • The multiplicative operators *, /, and % (§15.17)
  • The additive operators + and - (§15.18)
  • The shift operators <<, >>, and >>> (§15.19)
  • The relational operators <, <=, >, and >= (but not instanceof) (§15.20)
  • The equality operators == and != (§15.21)
  • The bitwise and logical operators &, ^, and | (§15.22)
  • The conditional-and operator && and the conditional-or operator || (§15.23, §15.24)
  • The ternary conditional operator ? : (§15.25)
  • Parenthesized expressions (§15.8.5) whose contained expression is a constant expression.
  • Simple names (§6.5.6.1) that refer to constant variables (§4.12.4).
  • Qualified names (§6.5.6.2) of the form TypeName . Identifier that refer to constant variables (§4.12.4).

Following from the definition of a compile-time constant expression, we have 4.12.4:

A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.

Finally, from 8.1.3:

Inner classes may not declare static members, unless they are constant variables (§4.12.4), or a compile-time error occurs.

like image 21
Steve P. Avatar answered Oct 13 '22 08:10

Steve P.