This question already has answers here:
Why Final variable doesn't require initialization in main method in java?
(4 answers)
Closed 4 years ago.
As per my knowledge, final variables must/can be initialized only once otherwise compiler is supposed to throw an error.
If the final instance variable x is not initialized an error is thrown but I faced no error when the local variable y is kept uninitialized in the following code:
import java.util.*;
public class test
{
final int x = 5;// if final variable x uninitialized, compilation error occurs
public static void main(String[] args)
{
final int y; // y is not initialized, **no error is thrown**
System.out.println("test program");
}
}
The local variable isn't used and therefore can be left uninitialized
You will get compile error when try to use it (even if it's not final):
System.out.println("test program" + y);
The local variable y may not have been initialized
The Java Language Specification does not state that a final variable must be assigned (emphasis mine):
A final variable may only be assigned to once.
And:
A blank final is a final variable whose declaration lacks an initializer.
So your y variable is a blank final, and since it's not referenced anywhere further in your code, it's perfectly fine to leave it unassigned.
import java.util.*;
public class test
{
final int x = 5;
public static void main(String[] args)
{
final int y;
System.out.println("test program");
y=6;
y=7;
}
}
y=7 will give error:The final local variable y may already have been assigned. Since it is a final variable, and it has been assigned to 6.
IMHO, a final local variable means once assigned, it cannot be re-assigned. But by final int y you are only declaring a final variable without assignment(initialization), which is legal in Java.(But in order to use it you still have to initialize it, or an error occurs.)
Update:
As commented below, you have noticed the difference between a class field final variable and a local final variable.
From Java Language Specification:
a final field must be definely assigned in the static initializer or the constructor:
8.3.1.2 final Fields
A field can be declared final (§4.12.4). Both class and instance variables (static
and non-static fields) may be declared final.
A blank final class variable must be definitely assigned by a static initializer of
the class in which it is declared, or a compile-time error occurs (§8.7, §16.8).
A blank final instance variable must be definitely assigned at the end of every
constructor of the class in which it is declared, or a compile-time error occurs (§8.8,
§16.9).
(Note that a non-final field can be left un-initialized)
2.A local variable(whether final or not) must be explicitly given a value before it is used:(chapter 4.12.5,P88)
• 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 per the definition of a final variable, they can be initialized only once. In your code, you haven't initialized 'y' and you're not using it anywhere as well.
But if you do the following,
final int y;
System.out.println(y);
you will get 'variable y might not have been initialized'
You will get an error when you try to use the declared final variable.
System.out.println(y);
Related
I was reading the question here : Java : in what order are static final fields initialized?
According to the answer
"except that final class variables and fields of interfaces whose
values are compile-time constants are initialized first ..."
I think this is not correct because the following will fail :
static {
String y = x;
}
public static final String x = "test";
In the static block, x is not recognized. Can anyone please comment if that answer is correct ?
The order of initialization doesn't change the fact that the JLS doesn't let you refer to variables before they're declared in various cases. This is described in JLS§8.3.3:
Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope (§6.3). Specifically, it is a compile-time error if all of the following are true:
The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C or a static initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
That's why your code gets this compilation erorr:
error: illegal forward reference
The statement that static fields that are constant variables are initialized first is indeed defined in JLS§12.4.2:
Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.
Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1).
...
Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.
As you can see, constant variables are initialized in step 6, but others in step 9.
This demonstrates the behavior:
public class Example {
static String y;
static {
y = foo();
}
static String foo() {
return x.toUpperCase();
}
public static final String x = "test";
public static void main(String[] args) throws Exception {
System.out.println(x);
System.out.println(y);
}
}
That compiles, and outputs:
test
TEST
In contast, if you change the x line so it's not constant anymore:
public static final String x = Math.random() < 0.5 ? "test" : "ing";
It compiles, but then fails because x is null as of y = foo();.
For the avoidance of doubt: I don't recommend using methods to initialize fields like that. :-)
As this answer states:
... they are initialized in the order in which they appear in the source.
You are absolutely right, your example fails, because you are trying to use a variable that is declared after the usage. Since static block are executed in order of the source code, you are absolutely correct and should suggest and edit for that answer, because this statement is invalid:
except that final class variables ... are initialized first.
This question already has answers here:
Why is it not possible to shadow a local variable in a loop?
(7 answers)
Closed 5 years ago.
I am new in Java and came across one OCJA-1.8 sample question where I am having some doubt. I need clarification on this behavior of JVM.
public class Test{
static int x=1;//**This is static class level variable**
public static void main(String[] args){
int[] nums={1,2,3,4,5};
for(int x:nums){ // Local variable declared for for-each loop.
System.out.println(x);
}
}
}
Why the JVM have not thrown the error as duplicate variable, For the variable which is declared inside for each loop 'int x'. As static variable has class level scope ?
The local variable hides the original static field somewhat, but it is not inaccessible:
Test.x
And for non-static fields:
this.x // not in this case
So it is allowed, and in effect one often sees:
public class Pt {
private final int x;
public Pt(int x) {
this.x = x;
}
}
Which prevents the need to introduce some convention (_x, mX).
What is not allowed:
void f() {
int x = 42;
if (true) {
int x = 13; // COMPILER ERROR
...
}
}
As this is bad style, causing confusion.
The inner variable declaration of x override the static one.
If you need to access the static variable you can access it with Test.x
The duplicate variable compilation error happens for two variables with the same name declared in the same scope : fields or method declaration scope.
In your example, each variable is declared in a distinct scope.
As a consequence, as you refer x in the method declaring x, by default it refers to the variable with the nearer scope available (the x local variable) that so shadows the other variable (the x field variable).
To reference the shadowed variable :
if it is a static field (your case), prefix it with the class name declaring it : Test.x
if it is an instance field, prefix it with the this keyword : this.x
When you have a local variable same as static variable, static variable of the class is shadowed by the local variable.
It doesn't throw an error because Java has the concept of shadowing. In essence, the variable with the lowest scope is used.
The static field is still accessible, you just need to fully qualify it:
for(int x:nums){
System.out.println(x); // Local x
System.out.println(Test.x); // static x
}
This can be confusing to a reader of your code and so should be avoided in most cases. If you find yourself with a field and local variable named identically, there's probably something up and you should re-evaluate how you've named your variables.
In your specific case, x is not a descriptive name and both variables would benefit from better, more descriptive names.
In certain cases, such as within a constructor or setter method, it's beneficial to have local variables and fields with the same names, and this is where shadowing is a useful feature.
I have a doubt in static final variable.In the following program:
class StaticPuzzel2 {
public static void main (String[] args) {
}
final static int i;
static {
System.out.print ("\n\t"+ StaticPuzzel2.i);
i = 11;
System.out.print ("\n\t"+ StaticPuzzel2.i);
System.out.print ("\n\t"+ i);
}
}
Even though the final variable has not been initialized it is not throwing error. Why it is so?
I assume you're wondering why it doesn't throw an error when you access it before setting it to 11. The reason is, that the variable is actually initialized with the default value (zero), and changed at runtime just like any other variable.
When using a static initialization block, the final modifier only makes sure you are assigning a value to the variable only once. What it doesn't do, is making it non-existent before that has happened.
Because it has been already initialized in static block. If you comment out that line it will give a compilation error.
You are initializing static variable in static block. That's why.
Try this:
final static int i = 0;
From java specs :
A variable can be declared final. A final variable may only be assigned to once. It is a compile-time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment
So it doesn't actually means that if should be initialized at declaration. But it means that it can only be assigned once and this assignment can be part of declaration or initializer blocks as in your case.
This is will give you error now.
You can check this answer for more details.
Java - Can final variables be initialized in static initialization block?
I have a program like this:
class Test {
final int x;
{
printX();
}
Test() {
System.out.println("const called");
}
void printX() {
System.out.println("Here x is " + x);
}
public static void main(String[] args) {
Test t = new Test();
}
}
If I try to execute it, i am getting compiler error as : variable x might not have been initialized based on java default values i should get the below output right??
"Here x is 0".
Will final variables have dafault values?
if I change my code like this,
class Test {
final int x;
{
printX();
x = 7;
printX();
}
Test() {
System.out.println("const called");
}
void printX() {
System.out.println("Here x is " + x);
}
public static void main(String[] args) {
Test t = new Test();
}
}
I am getting output as:
Here x is 0
Here x is 7
const called
Can anyone please explain this behavior..
http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html, chapter "Initializing Instance Members":
The Java compiler copies initializer blocks into every constructor.
That is to say:
{
printX();
}
Test() {
System.out.println("const called");
}
behaves exactly like:
Test() {
printX();
System.out.println("const called");
}
As you can thus see, once an instance has been created, the final field has not been definitely assigned, while (from http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.2):
A blank final instance variable must be definitely assigned at
the end of every constructor of the class in which it is
declared; otherwise a compile-time error occurs.
While it does not seem to be stated explitely in the docs (at least I have not been able to find it), a final field must temporary take its default value before the end of the constructor, so that it has a predictable value if you read it before its assignment.
Default values: http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.5
On your second snippet, x is initialized on instance creation, so the compiler does not complain:
Test() {
printX();
x = 7;
printX();
System.out.println("const called");
}
Also note that the following approach doesn't work. Using default value of final variable is only allowed through a method.
Test() {
System.out.println("Here x is " + x); // Compile time error : variable 'x' might not be initialized
x = 7;
System.out.println("Here x is " + x);
System.out.println("const called");
}
JLS is saying that you must assign the default value to blank final instance variable in constructor (or in initialization block which is pretty the same). That is why you get the error in the first case. However it doesn't say that you can not access it in constructor before. Looks weird a little bit, but you can access it before assignment and see default value for int - 0.
UPD. As mentioned by #I4mpi, JLS defines the rule that each value should be definitely assigned before any access:
Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.
However, it also has an interesting rule in regards to constructors and fields:
If C has at least one instance initializer or instance variable initializer then V is [un]assigned after an explicit or implicit superclass constructor invocation if V is [un]assigned after the rightmost instance initializer or instance variable initializer of C.
So in second case the value x is definitely assigned at the beginning of the constructor, because it contains the assignment at the end of it.
If you don't initialize x you'll get a compile-time error since x is never initialized.
Declaring x as final means that it can be initialized only in the constructor or in initializer-block (since this block will be copied by the compiler into every constructor).
The reason that you get 0 printed out before the variable is initialized is due to the behavior defined in the manual (see: "Default Values" section):
Default Values
It's not always necessary to assign a value when a field is declared.
Fields that are declared but not initialized will be set to a
reasonable default by the compiler. Generally speaking, this default
will be zero or null, depending on the data type. Relying on such
default values, however, is generally considered bad programming
style.
The following chart summarizes the default values for the above data
types.
Data Type Default Value (for fields)
--------------------------------------
byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char '\u0000'
String (or any object) null
boolean false
The first error is the compiler complaining that you have a final field, but no code to initialize it - simple enough.
In the second example, you have code to assign it a value, but the sequence of execution means you reference the field both before and after assigning it.
The pre-assigned value of any field is the default value.
All non-final fields of a class initialize to a default value (0 for nummeric data types, false for boolean and null for reference types, sometimes called complex objects). These fields initialize before a constructor (or instance initialization block) executes independent of whether or not the fields was declared before or after the constructor.
Final fields of a class has no default value and must be explicitly initialized just once before a class constructor has finished his job.
Local variables on the inside of an execution block (for example, a method) has no default value. These fields must be explicitly initialized before their first use and it doesn't matter whether or not the local variable is marked as final.
Let me put it in the simplest words I can.
final variables need to be initialized, this is mandated by the Language Specification.
Having said that, please note that it is not necessary to initialize it at the time of declaration.
It is required to initialize that before the object is initialized.
We can use initializer blocks to initialize the final variables. Now, initializer blocks are of two types
static and non-static
The block you used is a non-static initializer block. So, when you create an object, Runtime will invoke constructor and which in turn will invoke the constructor of the parent class.
After that, it will invoke all the initializers (in your case the non-static initializer).
In your question, case 1: Even after the completion of initializer block the final variable remains un-initialized, which is an error compiler will detect.
In case 2: The initializer will initialize the final variable, hence the compiler knows that before the object is initialized, the final is already initialized. Hence, it will not complain.
Now the question is, why does x takes a zero. The reason here is that compiler already knows that there is no error and so upon invocation of init method all the finals will be initialized to defaults, and a flag set that they can change upon actual assignment statement similar to x=7.
See the init invocation below:
As far as I'm aware, the compiler will always initialize class variables to default values (even final variables). For example, if you were to initialize an int to itself, the int would be set to its default of 0. See below:
class Test {
final int x;
{
printX();
x = this.x;
printX();
}
Test() {
System.out.println("const called");
}
void printX() {
System.out.println("Here x is " + x);
}
public static void main(String[] args) {
Test t = new Test();
}
}
The above would print the following:
Here x is 0
Here x is 0
const called
If I try to execute it, i am getting compiler error as : variable x might not have been initialized based on java default values i should get the below output right??
"Here x is 0".
No. You are not seeing that output because you are getting a compile-time error in the first place. Final variables do get a default value, but the Java Language Specification (JLS) requires you to initialize them by the end of the constructor (LE: I'm including initialization blocks here), otherwise you'll get a compile-time error which will prevent your code to be compiled and executed.
Your second example respects the requirement, that's why (1) your code compiles and (2) you get the expected behaviour.
In the future try to familiarize yourself with the JLS. There's no better source of information about the Java language.
I am working on a class that has some fields with final access modifier like: final textField and I am allowed to assign to them forsome reason. When I change them to static final I can no longer assign anything to them (it complains that they are final like it should have done in the first place). Any ideas why this is happening ?
Example for the first case:
final LabelField label_title;
label_title = new LabelField(
"Press the button to launch the speed test",
LabelField.FIELD_HCENTER);
You can assign final fields in constructor, you can't assign static final fields in a constructor. You shouldn't change static fields in a constructor in any case.
When a field is defined as final, it has to be initialised when the object is constructed, i.e. you're allowed to assign value to it inside a constructor.
A static field belongs to the class itself, i.e. one per class. A static final field is therefore not assignable in the constructor which is one per object.
Hope it makes sense to you!
The value of final members can't be changed. But it is allowed to initialize a final instance field in the constructor. This is not allowed for class members. The next snippets shows what's allowed and what's not allowed:
public class Final {
final static Integer INT1; // compile error
final static Integer INT2 = new Integer(2);
final Integer int3;
final Integer int4 = new Integer(4);
public Final() {
int3 = new Integer(3);
int3 = new Integer(3); // compile error
}
}
From the JLS - final fields: -
A field can be declared final (§4.12.4). Both class and instance
variables (static and non-static fields) may be declared final.
It is a compile-time error if a blank final (§4.12.4) class variable
is not definitely assigned (§16.8) by a static initializer (§8.7) of
the class in which it is declared.
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, JLS clearly specifies that you should assign your static final fields in static initializer block. You can't assign them in any constructor.
So, if you have a static final field, you should either initialize them in place, or you can use a Static Initializer Block to initialize them.
Moreover, you can assign your final fields in constructor, provided you don't change the assignment later on anywhere..
A static field belongs to the class, which is (should be) initialized right after the class is loaded, and that is when it must be initialized (the value needs to be assigned) if it is final.
Constructor is called when someone needs to instantiate the class. Now if you change the value of that static final field in the constructor means that you are trying to change (or re-assign) it's value.
But doing that in a static initializer (static { /* assign value here */ }) should be fine, which is meant for initialization of the class.