Why does not initializing a local final variable compile? This behavior seems to contrast final fields where not initializing a gives a compilation error.
class Test {
final Test test1; // doesn't compile
public Test(){
final Test test2; // does compile
}
}
What's the logic behind this choice?
This comes from the rules of the JLS.
From 4.12.4
It is a compile-time error if a final variable is assigned to unless it is definitely unassigned (§16) immediately prior to the assignment.
From 4.12.5
A local variable (§14.4, §14.14) must be explicitly given a value before it is used, by either initialization (§14.4) or assignment (§15.26), in a way that can be verified using the rules for definite assignment (§16).
From 8.3.1.2
A blank final instance variable must be definitely assigned (§16.9) at the end of every constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs.
So the technical reason why that works is because it's not forbidden. Fields must be initialized by the time the object is constructed. Local variables only need to be initialized before they're used.
The logic behind it is that a class variable might be referenced from another object, so it needs to be initialized by the time that another object might have an initialized reference to it. A local variable doesn't escape it's scope though, so the compiler can guarantee that it's not referenced as long as it's not used within that scope.
Related
I just found that Java handles variable initialization in different ways.
Case-1:
class A {
boolean x;
public static void main(String[] args) {
A a = new A();
System.out.println(a.x);
}
}
When I ran above program it shows like "false" as output. But now I am posting other piece of code:
Case-2:
class A {
public static void main(String[] args) {
boolean x;
System.out.println(x);
}
}
Now, above piece of code shows that
java.lang.Error: Unresolved compilation problem:
The local variable x may not have been initialized
Why the same thing is handled in very different ways?
Thanks in advance!
From the Oracle documentation on Java Primitive Data Types:
Local variables are slightly different; the compiler never assigns a
default value to an uninitialized local variable. If you cannot
initialize your local variable where it is declared, make sure to
assign it a value before you attempt to use it. Accessing an
uninitialized local variable will result in a compile-time error.
So this is an interesting nuance. If a primitive type variable is locally declared, you must specify a value for it.
There are three distinct types of variables:
static variables - within class;
member variables - within object
local variables - having scope limited to a function or block of code
Assumming the variables are not final.
The first two default to 0 or false (when var is a primitive) or
null (when var is an object) when accessed for read. The last one must be set to a value prior to reading, otherwise the code will not compile.
All of variable types (local, member, static) must be assigned a particular value if defined as final. Such Initialisation of static final variable can be an inline assignment to a value or it can be done in static initialisation block. Initialisation of final member variables can be done inline, within Initialisation block or within object's constructor (most common - best practice).
Final local variables initialized inline. There is also "effectively final" variable that is inferred by compiler when it sees that variable will not be changed. Final variables allow compiler to treat and optimize handling of data.
Thats just a couple of basic items to start with. Hope it is helpful.
Cheers.
If this question is about why local variables are treated different from non-final member variables: in the example above I do not see any use do declare boolean x; instead of boolean x = false;, but the last one makes the intent of the programmer clear. Also you are allowed to declare boolean x; if you initialize x later. Here the compiler error you get is helpful so you don't forget to initialize it in some rare edge case. The compiler couldn't check that if it would be initialized by default.
It's also common to have code like
int i;
if (a > b)
i = 8; // loong code
else
i = 42; // loong code
Initializing i would be useless here.
Static and non-static members (non final) are different because the compiler always nulls all fields before running initializers and constructors. Not initializing them to 0 manually is a slight performance improvement.
Explanation
Your two examples use different kinds of variables:
a field (also called instance variable, or member)
a local variable
You can only use a variable if it has a value / refers to an instance. For fields, if you do not explicitly assign a value, they are defaulted. That is not the case for local variables, thus the error.
The default value is null for objects and special values for primitives, like 0, 0.0, false and similar.
Java Language Specification
The JLS clearly defines this behavior and explains how it works. Take a look at chapter 4.12.5 Initial Values of Variables where it states (relevant excerpts):
Every variable in a program must have a value before its value is used:
Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2):
For type boolean, the default value is false.
A local variable (§14.4, §14.14) must be explicitly given a value before it is used, by either initialization (§14.4) or assignment (§15.26), in a way that can be verified using the rules for definite assignment (§16 (Definite Assignment)).
As part of JVM Loading, Linking and Initalizing, When the
static fields
final static fields
in Class
allocating in memory
init as default value
init as real value
In the case of the static final variables, I think that everything happens in the Loading step, because all values are already in Constant Pool.
But I can not figure out what's going on with the static fields. In principle, in the written documantation that they are initialized with default value in the Preparation step.
Preparation involves creating the static fields for a class or interface and initializing such fields to their default values (§2.3, §2.4). This does not require the execution of any Java Virtual Machine code; explicit initializers for static fields are executed as part of initialization (§5.5), not preparation.
But in this source (Class Variables paragraph) loading the static fields initialization occurs already in the Loading step. This makes sense because at the end of the loading step an instance of the class object is created, and it must contain room for the static fields.
Before a Java virtual machine uses a class, it must allocate memory from the method area for each non-final class variable declared in the class.
So I'd like to know what the right fact is in this case.
Generally, if there is some mismatch between the official specification and some article on the internet, you can safely assume that the specification has the last word and the article is wrong. This will serve you in 99.99% of all cases.
That’s especially true when it comes to the Java Virtual Machine, where articles notoriously mix up the steps of your question (“Loading, Linking, and Initializing”), and also regularly mix up formal steps and implementation details.
The article you’ve linked, does it wrong in several aspects:
Not every static final field is a compile-time constant. Only static final fields of primitive types or String are compile-time constants, if they are immediately initialized with a compile-time constant. Consider
static final String CONSTANT1 = ""; // compile-time constant
static final String CONSTANT2 = CONSTANT1; // compile-time constant
// but
static final String NO_CONSTANT1 = CONSTANT1.toString(); // not a constant expression
static final String NO_CONSTANT2; // no initializer
static {
NO_CONSTANT2 = ""; // assignment in class initializer, valid, but not constant
}
static final BigInteger NO_CONSTANT3 = BigInteger.ONE; // neither primitive nor String
For compile time constants, every ordinary Java language read access is replaced by the constant value at compile-time, still, the identifiers exist and can be inspected via Reflection or accessed by byte code not generated from Java language source code. Whether the JVM treats constant fields specially, when it comes to their storage, is an implementation detail, but usually, implementors try to avoid special treatment, unless there’s a true benefit.
The formal specification describes the constant variables as-if having a storage like any other variable, but of course, implementations may omit this, if they are capable of still retaining the mandated behavior (e.g. make the values available to Reflection).
The initialization of both, constant and non-constant static variables is clearly specified as part of the Initialization (though not at the same time):
Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC. Then, initialize each final static field of C with the constant value in its ConstantValue attribute (§4.7.2), in the order the fields appear in the ClassFile structure.
…
9. Next, execute the class or interface initialization method of C.
The “class or interface initialization method” is the method named <clinit> at the bytecode level, which contains all initializers of non-constant static fields as well as any code in static { … } blocks.
Class variables and the constant pool are different things. The constant pool contains the symbolic names of fields as well as values for compile-time constants (which, by the way, may include non-static fields as well).
The values of the constant pool can be used to construct the actual runtime values, e.g. the byte sequence describing a string has to be converted to a reference to an actual String object and the primitive types may undergo Endianess conversions. When this processing happens as part of step 6 described in JVMS§5.5, as cited above, subsequent access to the field will consistently use the result of this process.
My understanding is that the memory allocation is done during the preparation, and the execution of the initializers during initialization. This doesn't contradict either of the sources.
To be precise,
Instance variables will be stored on the heap.
local variables on the stack(in case of variable not a
primitive[reference variable] reference variables live on stack and
the object on heap ). Only method invocation and partial results will
be stored in stack not the method itself.
Static variables and Methods(including static and Non Static) on the
Method Area. Static methods (in fact all methods) as well as static variables are stored in the PermGen section , since they are part of the reflection data (class related data, not instance related).
For static variables, if you do not initialize a variable, default value would be stored before object preparation (JVM takes care of this) but for Final Static, you need to initialize the variable before the object is created i.e. when we try to create a new object calling the constructor, before the object is returned to the reference variable, value need to be initialized else it is a compile time error.
Answers to your questions:
Static variable in Java belongs to the class and
initialized only once when the class is invoked (if not initialized - Lazy Initialization).
Static final variable is initialized at the time of class loading in
the method Area, as it is already initialized in the code (early initialization).
There wont be any change in the allocating in memory for static and final static.
public class Object {
public static final int i;
static{
i=0; // comment this line gives you compile time error
}
/**
* #param args
*/
public static void main(String[] args) {
}
}
We already do understand that non-static inner classes cannot have any member which has a static keyword with it. Yet we see, static member variables with final is being used and encouraged. Can anyone explain why?
Another observation:
final static String abc = "I Love Food"; //works fine
whereas:
final static String abc = null; //is discouraged and gives error.
Read following JLS section (§8.1.3) for rules about usage of static/non-static members in an inner class.
Inner classes may not declare static initializers (§8.7) or member
interfaces, or a compile-time error occurs.
Inner classes may not declare static members, unless they are constant
variables (§4.12.4), or a compile-time error occurs.
Note this line above - "unless they are constant variables", which answers your question. When you declare a primitive or String as public static final then it becomes a "constant variable" and hence you are able to use it in a non-static inner class because it doesn't break the compilation rules.
Now, why it doesn't break compilation rules because when you declare a constant variable and initialize it then compiler could deterministically say that this would be value of this variable, while if you do not initialize it then compiler cannot deterministically say that this would be value of this variable and wouldn't be sure if it could be modified at runtime, and you cannot change a final value once it is been assigned.
Read rule related to final variable in this JLS section (§4.12.4)
We already do understand that non-static inner classes cannot have any member which has a static keyword with it.
Evidently your understanding is not complete. Section 8.1.3 of version 8 of the JLS specifies, in part,
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).
(Emphasis added.) Thus an inner class can have static members; there are just fairly strong restrictions on them.
Yet we see, static member variables with final is being used and encouraged. Can anyone explain why?
(Emphasis in the original.) I don't think I often see such usage being encouraged, per se. Nevertheless, it's a sensible way to keep the scope of such constants narrow, which is a good practice.
You furthermore ask about why a static final inner class member cannot be initialized to null. I cannot provide a rationale for that, but the actual rule is spelled out in the JLS, in the definition of a "constant variable" (referenced by the previous excerpt) in section 4.12.4:
A constant variable is a final variable of primitive type or type
String that is initialized with a constant expression (§15.28).
Of course, that depends on the definition of a "constant expression", which is a bit lengthy to present in its entirety. It boils down to an expression of primitive or String type that involve only integer literals, String literals, names designating constant variables, and a fairly large subset of Java's operators. And this brings us to the point: null is neither of primitive type nor of type String, therefore it cannot appear in a constant expression, therefore a variable is not a "constant variable" if it has null or an expression containing null as its initializer. Such a variable, not being a constant variable, cannot appear in an inner class.
If you look at this Accepted Answer Why does Java prohibit static fields in inner classes the referenced section will give you the answer. A final static field is treated as Java's compile time constant.
I was wondering is a variable could be both instance and constant? For example would
private final int Min=25;
be both an instance variable and a constant variable?
The Java Language Specification has a chapter on variables.
A variable is a storage location and has an associated type, sometimes
called its compile-time type, that is either a primitive type (§4.2)
or a reference type (§4.3).
There are different types of variables: class, instance, local, method parameter, exception parameter in catch block, constructor parameter, and array components.
There are also final variables which can only be assigned once.
If you declare a non-static field in a class, that is considered an instance variable.
The JLS also says
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.
So yes, yours is both an instance and constant variable.
From Chapter 4 of the Java Language Specification
In section 4.12.3
An instance variable is a field declared within a class declaration without using the keyword static
In section 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.
So, yes, this is both a constant variable and an instance variable.
Feel free to use the term "constant variable". It sounds oxymoronic, but the JLS uses it, so you are fine to do so.
Yes, your example would be both an instance and a constant.
There are reasons for having an instance variable that can't be changed.
One is having clear and easy to read code. When you see a variable as final early on, you dont have to worry later on in the program if it is changing value or reference. This allows you to focus on other parts of the program where variables actually are changing.
Take a look at JLS for more info on variables
Instance Variable : an instance variable is a variable defined in a class (i.e. a member variable), for which each object of the class has a separate copy, or instance.
For example :
class MyClass {
int a; // instance variable;
People p; // instance variable;
static int b; // not instance variable. because all instances of class MyClass use same variable b
static People community; // not instance variable with same reason.
}
Constant : a constant is an identifier whose associated value cannot typically be altered by the program during its execution. In Java, there isn't no real constant as C#. In C#, you declare constant is :
// C# Code
const int a = 3; // true
const int a; // wrong. because constant must permently have value. because it cannot have another values in their life.
But in Java, there is just : a variable that you can initialize only one time. and you use it final :
// Java Code
final int a = 3; // true
final int b; // still true. you can declare it later
So. combine above knowledge, you can say your example : private final int Min=25; is both instance variable and "const" variable (java doesn't have const variable, remember)
Hope this help :)
An instance variable is a variable that every instance of a class is going to have its own version of. For example, if you have a Car class, an instance variable of Car might be color. Each time you make a new instance of Car, you can set its color instance variable.
A constant just means that it is unable to change after assignment -- it must also be initialised with a constant expression (thanks David!). So for the Car class, you could instantiate a new Car object with a specific color instance variable. In the Car class code, you could use the final keyword to make the color unchanging after it is set.
Yes, an instance variable can be defined as a constant.
Why a method-local inner class can't use variables declared inside the enclosing method except those marked final, i know that the variables declared inside the enclosing method might vanishes while the inner class instance remains valid, but what has changed when this variable/s is declared final?
The reason is that it is specified in the Java Language Specification #8.1.3
Any local variable, formal parameter, or exception parameter used but not declared in an inner class must be declared final.
Also note that project lambda (java 8), which aims at introducing closures in java (to replace anonymous classes), introduces the notion of effectively final which will allow you to use a non final variable within a lambda expression as long as you don't modify it within the closure.
When the variable is final, a copy is placed in the inner class. i.e. it still can't access the variable, but it has a copy it can use.
You can see these copies if you use reflection or with a debugger.
The reason is [ Actually Conclusion from Where are Java final local variables stored? ] : final variables are copied by the compiler into a hidden member variable of the inner class that references it. This way, they are guaranteed to not change after the copy has been made.
Also might be : The Method-Local Inner Class which is on the heap and the variable which is on the stack have different scope. But if the local variable is marked by final, it is stored on the heap.
Now at first i would like to light upon
Does final local variables get stored on a heap instead of stack
?
Explanation: Now after some researching in SO i found out that all local variable (final or not) stored into the stack and go out
of scope when the method execution is over. But about final
variable JVM take these as a constant as they will not change after
initiated . And when a inner class try to access them compiler create
a copy of that variable (not that variable it self) into the heap
and create a synthetic field inside the inner class, so even when
the method execution is over it is accessible because the inner class
has it own copy. Synthetic field are filed which actually doesn't
exist in the source code but compiler create those fields in some
inner classes to make those field accessible. In simple word hidden
field.
So final variable also stored in stack but the copy that variable which a inner class have stored in heap.
So now think about it.The local variables of the method live on the stack and exist only for the lifetime of the method. We already know that the scope of a local variable is limited to the method the variable is declared in. When the method ends, the stack frame is blown away and the variable is history. But even after the method completes, the inner class object created within it might still be alive on the heap if, for example, a reference to it was passed into some other code and then stored in an instance variable. Because the local variables aren't guaranteed to be alive as long as the method local inner class object is, the inner class object can't use them. Unless the local variables are marked final. And it is beneficial making variable final as it can remain like synthetic field.
Final ensures that you won't lose the reference to that variable. You don't want your inner class to destroy or lose your reference since you might continue using it in the context where was declared.