javac treating static final differently based on assignment method - java

When I compile:
public static final boolean FOO = false;
public static final void fooTest() {
if (FOO) {
System.out.println("gg");
}
}
I get an empty method fooTest() {}. However when I compile:
static boolean isBar = false;
public static final boolean BAR = isBar;
public static final void fooTest() {
if (BAR) {
System.out.println("gg");
}
}
the if statement is included in the compiled class file. Does this mean there are two different "types" of static final in java, or is this just a compiler optimization?

In the first case, the compiler does an optimization. It knows Foo will always be false and kill the code than will never be reached.
In the second case, you are assigning the value of the non-final variable isBar to BAR. The compiler can't tell if the variable isBar has been modified somewhere else, especially if it is not private. Therefore it is not sure of the value of BAR. Therefore he can not do the optimization.

It is purely a case of compiler optimization where it ignores a direct assignment and does consider indirect assignment of literals.

In the first case static final fields are constants which are known at compile time. So the compiler optimizes and inlines the constant.
In the second case the field is non-final variable and cannot be inlined by the compiler as it can change.
class Test{
public static final boolean BOOL = true; //CONSTANT KNOWN AT COMPILE TIME
public void someMethod(){
while(BOOL){
//some code
}
}
//OPTIMIZED VERSION DONE BY COMPILER
public void someMethod(){
while(true){ //There is no need for accessing BOOL if it is not going to change and compiler understands that so inlines the value of constant
}
}
}
You can look at the compiled code using some de-compiler tools and you will find the optimized method that I have written in the class file.

There could be only one existing static value within the memory. In the first block, the static final variable FOO is set false value which in known to the compiler and hence it optimizes the if statement in it. But in second statement, the BAR final static variable is assigned isBar static variable value, which in turn makes the compiler not to optimize the if statement (since isBar could be any Boolean value and it cannot be determined because java supports polymorphism and values are assigned to variables dynamically during run time.), hence static variables memory position in the second block is important to the compiler to determine its value, where as in the first block the value false is known without any assignment between different variables and it is optimized.

Related

why Java final variables cannot be assigned a value in the setter method?

Non-static final variables can be assigned a value only once.
But why this assignment can happen only either within a declaration or in the constructor?
A final variable is defined to be immutable i.e., the value assigned to it will be the one and only for that variable x. As one can read from the JLS(§4.12.4.)
A variable can be declared final. A final variable may only be
assigned to once.
Now the constructor is just like any other method, except that it is the one that gets executed first when an object (non-static) is created from the class.
Hence, final variables can be assigned through constructors.
For example take the following code:
public class Test {
public final int x;
public Test(int x) {
this.x = x;
}
}
Compiler accepts this invocation because it is guaranteed that for that particular object its class's constructor gets invoked first and doesn't invoked again (i.e. constructor gets invoked one and only one time during the entire lifetime of object.)
However following code throws error: Non-static field 'x' cannot be referenced from a static context
public class Test {
public final int x;
static {
x = 5;
}
public Test(int x) {
this.x = x;
}
}
Since x is not a static field, it cannot be initiated within a static block.
This code would also throw error: Cannot assign a value to final variable 'x'
public class Test {
public final int x;
public Test(int x) {
this.x = x;
}
public void setX(int x) {
this.x = x;
}
}
That is because it is not guaranteed for this object, that the method setX would run first and only once. The programmer could call this method multiple times. Hence, the compiler throws an error.
So there is no way to make a variable "initializable" only once (e.g.,
a setter would block if variable was already assigned before) solely
with java syntax? I thought final might work this way but now I see
it's not.
For your question, you could simply make a variable private and add the condition to the setter method to add value only if variable is null.
For example:
public class Test {
private Integer x;
public Test() {
}
public Test(int x) {
this.x = x;
}
public void setX(int x) {
if (null == this.x) this.x = x;
}
public static void main(String[] args) {
Test y = new Test(5);
System.out.println(y.x);
y.setX(20);
System.out.println(y.x);
}
}
This is not thread safe by the way. I just added a simple example.
What does the keyword final mean in Java?
When used in a class declaration, it means that the class cannot be extended.
When used in a method, it means that the method cannot be overridden.
When used in a method parameter, it means the value of such parameter cannot be changed inside the method. (local constant)
When used in a class field ("variable), it means that it is a global constant.
Values for constants must be resolved at compile time. And, as the word implies, constants fields cannot change value. Therefore, the compiler does not allow the value to be set from a setter (mutator) method.
Contrary to what many believe, for a field to be constant, it does not have to be declared static and final. That said, since the value of a constant cannot be changed, each class instance will share the same value. Therefore, explicitly making them static reenforces this notion.
There is a fifth use of the keyword final and this is when used when local variables are declared. This is a more lengthy explanation.
What happens when you compile code?
I updated my answer because I think part of the problem is that some developers don't quite understand what happens when the code is compiled. As I mentioned before, constant values are resolved at COMPILE TIME. To understand this concept, consider the following example:
public class MyClass {
private final double PI = 3.14159;
// rest of class left out intentionally
}
If I compile this class on my laptop and then I deploy the code to some remote server, how does the server know that the global constant field PI has an assigned value of 3.14159? This is because when I compile this code, this value gets packaged with the byte code. The class constructor doesn't come into play at all in this case. HOWEVER, if the constant field is initialized to its DEFAULT value, then permanent (constant) value may be assigned via the constructor
public class MyClass {
private final double PI; // default value of 0.0
public MyClass(double value) {
PI = value;
}
// rest of code omitted intentionally
}
Here's where declaring a constant as static makes a difference. If a constant is also static, you can't do the above because calling a constructor implies that you can have multiple instances of MyClass and each instance could set a different value. This is clearly a violation of what a static member is. So, if you MUST declare a field as both static and final, understand that you cannot assign a value using this second approach. Only the first one I showed is allowed.
Final Stop's a Variable’s Reassignment
a short simple answer:
Use the keyword final when you want the compiler to prevent a variable from being re-assigned to a different object.
Whether the variable is a static variable, member variable, local variable, or argument/parameter variable, the effect is entirely the same.
Hope this helps friend =)
#StaySafe

Access to final field via getter before its initializing

First of all, this question has forward relation to these nice questions:
1) Use of uninitialized final field - with/without 'this.' qualifier
2) Why isn't a qualified static final variable allowed in a static initialization block?
But I will ask it in slightly another angle of view. Just to remember: mentioned questions above were asked about access to final fields using keyword this in Java 7.
In my question there is something similar, but not the same. Well, consider the following code:
public class TestInit {
final int a;
{
// System.out.println(a); -- compile error
System.out.println(getA());
// a = a; -- compile error
a = getA();
System.out.println(getA());
}
private int getA() {
return a;
}
public static void main(String[] args) {
new TestInit();
}
}
And output is:
0
0
As you can see there are two unclear things here:
There is another legal way to access non-initialized final field: using its getter.
Should we consider that an assigment a = getA(); as legal for blank final field and that it will always assign to it its default value like for non-final field according to JLS? In other words, should it be considered as expected behaviour?
What you're really running into is the inference ability of the compiler.
For your first compiler error, that fails because the compiler definitely knows a is not assigned. Same with the second a=a (you can't assign from a because it's definitely not assigned at that point).
The line that works a=getA() is a first, single, definite assignment of a, so that's fine (regardless where the value comes from; the implementation of getA() doesn't matter and isn't assessed at this point).
The method getA() is valid and can return a because the instance initializer has definitely assigned a value to a.
It makes sense to a human looking at it, but it's not an inference built into the compiler. Each block, independently evaluated, is valid.

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

In Java why would one initialize an int variable with 0 when it will be assigned 0 only by default when declared?

What purpose does it serve?
Just read an example in a book where the author has done so.
int numOfGuesses=0;
The automatic assignment to zero only applies to members, not to local variables. If it is a local variable and the = 0 is omitted then that variable has no value, not even zero. Attempting to use the value before it is assigned will result in a compile error. For example this code attempts to use an uninitialized local variable:
public class Program
{
public static void main(String[] args)
{
int numOfGuesses; // local variable
System.out.println(numOfGuesses);
}
}
and produces this compile error:
Program.java:6: variable numOfGuesses might not have been initialized
System.out.println(numOfGuesses);
Whereas this code using a member works and outputs zero:
public class Program
{
int numOfGuesses; // member variable
public void run()
{
System.out.println(numOfGuesses);
}
public static void main(String[] args)
{
new Program().run();
}
}
For members I tend to assign to zero explicilty if my code uses the fact that the initial zalue is zero, and omit the assignment if my code doesn't use the initial value (for example if it the value is assigned in the constructor or elsewhere). The result is the same either way, so it's just a style issue.
It's more explicit; some people like. Note that this applies only to fields -- local variables need to be initialized; there are no defaults.
The Java compilation and runtime differ.
When running the program, all classes are loaded with class loaders and they do the following:
This is done when class is used for the first time. Their execute order is defined by their order in the code.
run static blocks
static{
//do something here
}
initialize static variables
public static int number;
This will be initialized to zero 0;
The next group of initializations done is when creating an object.Their execute order is defined by their order in the code.
run non-static block
{
// do something here
}
initialize non-static(instance) variables
public int instance_number;
And this is when and why there is default initialization!
This is not true for methods because they don't have similar mechanism as classes.
So basically this means that you will have to initialize EXPLICITLY each method variable.enter code here

Categories