Why final field variable can not assign to blank in Java? - java

Like other variables, i want to assign final field type variable to blank but initialization is blocking by Java. What is the its logic? Maybe i want to use default values of my variables? for int = 0, string = null boolean = false etc...
public class Hello {
static final int myNumber; /* it is giving "The blank final field myNumber
may not have been initialized" error in Eclipse */
}

In Java, after you use the final keyword with a static variable, you must define the value at the point of declaration. You must give it some value and stick with it.

A final variable can only be initialized once, either via an initializer or an assignment statement. It does not need to be initialized at the point of declaration: this is called a "blank final" variable.
change your code
public class Hello {
final int myNumber;
public Hello(int num){
this.myNumber = num;
}
}
for static final variable use static block for initialization
static{
myNumber = 0;
}

From the Java specs : "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."

When you use the "final" modifier with a variable, you must initialize it then as it is the only time you're allowed to use the assignment operator(you can initialize once if you left it blank) on it ("="). Like parker.sikand said, you will get an error if you try to assign a value to it afterwards.
Also, an important note that final STRICTLY means that you cannot use the assignment operator. If the object that is "final" is a mutable object then of course the contents of that object can change without ever using the assignment operator.
EDIT: I believe a final variable has to be guaranteed to be initialized at SOME point in the program which is why you generally initialize it on declaration

Eclipse 2019-09 now proposes a quickfix for that:
Initialize 'final' fields
A Java quickfix is now offered to initialize an uninitialized final field in the class constructor.
The fix will initialize a String to the empty string, a numeric base type to 0, and for class fields it initializes them using their default constructor if available or null if no default constructor exists.

Related

JAVA: What is the advantage of static value loaded in compile time?

I write java code like this:
final int value=0;
When I use "Svace Static Analyzer" to anylyze the code,it shows:
This class contains an instance final field that is initalized to a compile-time static value, Consider making the field static---->
static final int value=0;
I know static value is loaded in compile time. Can anyone explain the advantage of compile load?
Scenario 1:
class Mango{
final int marker = 10;
}
In a class, when you declare a variable as final and initialize it during declaration, that means you do not want to modify it from anywhere.
In that case, all of the created objects of the class maintained a similar value for this variable.
On the other hand, whenever we declare a variable as static, then at the class level a single variable is created which is shared with the objects. Any change in that static variable reflects to the other objects operations.
But actually, at points 1 and 2 we want to achieve point 3's behavior implicitly.
So, java force or suggest you create only one copy of the marker variable by declaring is static also.
class Mango{
final static int marker = 10;
}
Which is memory efficient, cleaner, and non-ambiguous.
Scenario 2:
public class Mango {
final int marker;
Mango(int m){
marker = m;
}
}
This type of declaration is totally different. In that case, every instance of the Mango class has its own marker variable, and it can be initialized only one time.
The first type of declaration ensures class-level final behavior and the second type of declaration ensures the object-level final behavior.

Java not printing default unitialized value

I understand that Java objects that are only declared but not initialized are defaulted to the null value, but then why doesn't the following compile and print out null?
String a;
System.out.println(a);
From section 16 of the JLS:
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.
Your code will work for non-final fields (instance or static variables) as they are initialized as per section 4.12.5) but will cause a compile-time error for local variables due to this.
The same would be true if a were a primitive variable. Here's a short but complete program showing all of this:
class Test {
static int x;
static String y;
public static void main(String[] args) {
System.out.println(x);
System.out.println(y);
int lx;
String ly;
System.out.println(lx); // Compile-time error
System.out.println(ly); // Compile-time error
}
}
Output of the first two lines once the non-compiling lines have been removed:
0
null
Fields of a class are initialized by default.
Like
class A {
String a;
public void doSomething() {
System.out.println(a); //prints null
}
}
But local variables must be explicitly initialized. So your code above won't work because a must be explicitly initialized.
You may want to read the Java Language Specification, section 4.12.5. Initial Values of Variables, where this behavior is explained in full detail.
The instance variables which are object references are always initialized to null. But the same is not the case with local variables.
You need to explicitly initialize the local variables.
e.g.
String a = null;
System.out.println(a);
Fields in java must be initialized before you access them.
The class properties(fields) of reference type (for example) can be not initialized explicitly because they are guaranteed to be null-initialized before object construction (i mean the constructor code execution). This is the guarantee that you wont access the uninitialized field.
There is no such logic about the local method fields so you must do it explicitly.

Do final (constant) instance (non-static) variables act like class (static) variables?

In the following example, the variable b is declared final, but not static. That means it's a constant instance variable. However, because it's constant, none of the Passenger objects can change its value. So isn't it better to declare it static and make it a class variable, so that there is only one copy to be used by all instantiated objects?
class Passenger {
int a;
final int b = 0;
void drive() {
System.out.println("I'm driving!");
}
}
The purpose of final but non-static variables is to have an object-wide constant. It should be initialized in the constructor:
class Passenger {
final int b;
Passenger(int b) {
this.b = b;
}
}
If you are always assigning a constant literal value (0) to the final variable, it doesn't make much sense. Using static is preferred so that you are only having a single copy of b:
static final int b = 0;
BTW I don't think having default access modifier was your intention.
It depends on the purpose of b. Usually constants are there for a specific purpose. If you make it static you could accidentally change it in some instance of that class and that will affect all the others.
If you have multiple instances of Passenger class, I would go for making it static. While this has little benefit when talking about an int variable, this could save some memory if you have complex objects. This is because a static variable belongs to a class, not to an instance, thus memory space for it will be reserved only once, and it will be referred by the class object itself, not by the instances. Of course, you should be aware that having b as a static variable means that the changes made on this variable will be reflected on all the classes that access this variable, but since you made it final this won't be the case.
Note also that with the code you've written, classes in the same package as Passenger will be able to read the b value by accessing it via Passenger.b (if static).
In java, the static attribute basically means: associated with the type itself, rather than an instance of the type.
In other words you can reference a static variable without creating instances of that type... Whereas in the case of just using final you'd need to instantiate the class.
So, yes, to answer your question, I'd say that you're right. :)
A final primitive is the same as a static final primitive (except more efficient)
A final reference to an immutable object the same as a static final reference of the same.
A final reference to a mutable object is NOT the same as a static final reference of the same.
final int i = 0;
// same as
static final int = 0;
final String hi = "Hello";
// same as
static final String hi = "Hello";
final List<String> list = new ArrayList<String>();
// is NOT the same as
static final List<String> list = new ArrayList<String>();
The only time the last example is the same is when you have a singleton. It is fairly common for singletons to be written with a confusion of static and non static fields and methods as the difference is not obvious. :|
A final variable is defined when you need a constant, so you can assign a value just once.
Using static, instead, you are defining a variable shared by all the objects of that type (like a global variable) and it is not associated with a certain object itself.

Reasons for restrictions on assignment of final variables

Why aren't final variables default initialized? Shouldn't the default constructor initialize them to default values if you are happy with the constant be the default value.
Why must you initialized them in the constructor at all? Why can you can't you just initialize them before using them like other variables?
ex.
public class Untitled {
public final int zero;
public static void main(String[] args)
{
final int a; // this works
a = 4; // this works, but using a field doesn't
new Untitled();
}
}
Untitled.java:2: variable a might not have been initialized
Why must you initialize static final variables when they are declared? Why can't you just initialize them before using them in any other method?
ex.
public class Untitled
{
public final static int zero;
public static void main(String[] args)
{
zero = 0;
}
}
Untitled.java:8: cannot assign a value to final variable zero
I'm asking these question because I'm trying to find a logical/conceptual reason why this won't work, why it isn't allowed. Not just because it isn't.
The idea behind a final variable is that it is set once and only once.
For instance final variables, that means they can only be set during initialization, whether at declaration, in a constructor, or an instance initialization block. For the variable to be set anywhere else, that would have to take place in a non-constructor method, which could be called multiple times - that's why this is off limits.
Similarly for static final variables, they can only be set at declaration or in a static initialization block. Anywhere else would, again, have to be in a method which could be called more that once:
public static void main(String[] args)
{
zero = 0;
main(null);
}
As for your first question, I'm assuming it's an error not to explicitly set a final variable in order to avoid mistakes by the programmer.
The Java Language Specification section 8.3.1.2 spells out the rules for final member variables:
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.
The JLS doesn't give reasons why the rules are they way they are. However, it might have come from experience in writing Java code, and the above rules are a way to avoid some common coding errors.
The concept of being final means that the variable value cannot change. If you could do as in your second example, then this variable would have been like any other one (i.e. not final)
I don't ave a good rational regarding your first question.
Because, when looking at your code, the Java compiler has no idea whether a given statement will be executed before an other statement. The only exceptions to this rule are code in constructors and implicit constructors, and that's why they're the only place that final fields can be assigned to.

Initialization of static final fields in Java

public class Main {
static final int alex=getc();
static final int alex1=Integer.parseInt("10");
static final int alex2=getc();
public static int getc(){
return alex1;
}
public static void main(String[] args) {
final Main m = new Main();
System.out.println(alex+" "+alex1 +" "+alex2);
}
}
Can someone tell me why this prints: 0 10 10? I understand that it's a static final variable and its value shouldn't change but it`s a little difficult to understand how the compiler initializes the fields.
It's an ordering problem. Static fields are initialized in the order that they are encountered, so when you call getc() to inititalize the alex variable, alex1 hasn't been set yet. You need to put initialization of alex1 first, then you'll get the expected result.
This situation is covered by JLS 8.3.2.3 "Restrictions on the use of Fields during Initialization".
The JLS rules allows the usage in your Question, and state that the first call to getc() will return default (uninitialized) value of alex.
However, the rules disallow some uses of uninitialized variables; e.g.
int i = j + 1;
int j = i + 1;
is disallowed.
Re some of the other answers. This is not a case where the Java compiler "can't figure it out". The compiler is strictly implementing what the Java Language Specification specifies. (Or to put it another way, a compiler could be written to detect the circularity in your example and call it a compilation error. However, if it did this, it would be rejecting valid Java programs, and therefore wouldn't be a conformant Java compiler.)
In a comment you state this:
... final fields always must be initialized at compile or at runtime before the object creation.
This is not correct.
There are actually two kinds of final fields:
A so-called "constant variable" is indeed evaluated at compile time. (A constant variable is a variable "of primitive type or type String, that is final and initialized with a compile-time constant expression" - see JLS 4.12.4.). Such a field will always have been initialized by the time you access it ... modulo certain complications that are not relevant here.
Other final fields are initialized in the order specified by the JLS, and it is possible to see the field's value before it has been initialized. The restriction on final variables is that they must be initialized once and only once during class initialization (for a static) or during object initialization.
Finally, this stuff is very much "corner case" behavior. A typical well-written class won't need to
access a final field before it has been initialized.
Static final fields whose values are not compile-time constant expressions are initialized in order of declaration. Thus when alex in being initialized, alex1 is not initialized yet, so that getc() returns default values of alex1 (0).
Note that result will be different (10 10 10) in the following case:
static final int alex1 = 10;
In this case alex1 is initialized by a compile-time constant expression, therefore it's initialized from the very beginning.
There is nothing special about static fields, it just that the compiler cannot workout that you are using a method which can access a field before its initialised.
e.g.
public class Main {
private final int a;
public Main() {
System.out.println("Before a=10, a="+getA());
this.a = 10;
System.out.println("After a=10, a="+getA());
}
public int getA() {
return a;
}
public static void main(String... args) {
new Main();
}
}
prints
Before a=10, a=0
After a=10, a=10
Class variables are not necessary to initialize, they are automatically set to their default values. If primitives (like int, short...) it's 0 (zero) for Objects it's null.
Therefore alex1 is set to 0.
Method variables must be initialized, otherwise you will get an compiliation error.
For a better explanation read http://download.oracle.com/javase/tutorial/java/javaOO/classvars.html

Categories