Java initialising a static field to itself - java

This code compiles (using Java 8), giving the warning The assignment to variable value has no effect:
package test;
public class Test {
private static int value;
static {
value = Test.value;
}
public static void main(String[] args) {
System.out.println(value);
}
}
The program outputs 0 as expected. But why does the compiler allow this, what is the use case?

Because variables in Java have a default value which is initialized before any other initialization, unless the initialization happens directly when declaring the variable. Indeed value is 0.
The warning seems reasonable, assigning a variable to itself has no apparent effect but I don't think it should be considered a compile type error since it's syntactically and semantically correct.

If as variable is assigned to itself, the compiler issues a warning, as in the following:
int x = 2;
x = x;
This warning is usually a sign of a programming problem, so for itself it is a good thing to have it, yet in the case that the variable is volatile, which will be the ONLIEST useful Use Case I can think off, the warning is incorrect.
int y = 0;
volatile int x = 2;
y = 3;
x = x;
The java memory model enforces that every thread reading x and y in that order is guaranteed to see the value 3 for y. This is because assigning to x in one thread and reading x in the other establishes a happens-before-ordering.
The assignment has no effect to the value of the variable but it does have a huge effect for concurrency.
Note that in the example above the warning can be suppressed by using
x = x + 0;
Yet there is no such hack for references. One Use Case that will hit you is when trying to sync the content of a int[]. One thread reads a member:
myarray[3]
and another thread writes the member:
myarray[3] = 2;
Because array members themselfes cannot be volatile, you have to make myarray volatile and add the following to the writing thread:
myarrray = myarray;

Related

try catch java -- java complaining that variable may not be initialized [duplicate]

When I try to compile this:
public static Rand searchCount (int[] x)
{
int a ;
int b ;
...
for (int l= 0; l<x.length; l++)
{
if (x[l] == 0)
a++ ;
else if (x[l] == 1)
b++ ;
}
...
}
I get these errors:
Rand.java:72: variable a might not have been initialized
a++ ;
^
Rand.java:74: variable b might not have been initialized
b++ ;
^
2 errors
It seems to me that I initialized them at the top of the method. What's going wrong?
You declared them, but you didn't initialize them. Initializing them is setting them equal to a value:
int a; // This is a declaration
a = 0; // This is an initialization
int b = 1; // This is a declaration and initialization
You get the error because you haven't initialized the variables, but you increment them (e.g., a++) in the for loop.
Java primitives have default values but as one user commented below
Their default value is zero when declared as class members. Local variables don't have default values
Local variables do not get default values. Their initial values are undefined with out assigning values by some means. Before you can use local variables they must be initialized.
There is a big difference when you declare a variable at class level (as a member ie. as a field) and at method level.
If you declare a field at class level they get default values according to their type. If you declare a variable at method level or as a block (means anycode inside {}) do not get any values and remain undefined until somehow they get some starting values ie some values assigned to them.
If they were declared as fields of the class then they would be really initialized with 0.
You're a bit confused because if you write:
class Clazz {
int a;
int b;
Clazz () {
super ();
b = 0;
}
public void printA () {
sout (a + b);
}
public static void main (String[] args) {
new Clazz ().printA ();
}
}
Then this code will print "0". It's because a special constructor will be called when you create new instance of Clazz. At first super () will be called, then field a will be initialized implicitly, and then line b = 0 will be executed.
You declared them, but not initialized.
int a; // declaration, unknown value
a = 0; // initialization
int a = 0; // declaration with initialization
You declared them, but you didn't initialize them with a value. Add something like this:
int a = 0;
You declared them but did not provide them with an intial value - thus, they're unintialized. Try something like:
public static Rand searchCount (int[] x)
{
int a = 0 ;
int b = 0 ;
and the warnings should go away.
Since no other answer has cited the Java language standard, I have decided to write an answer of my own:
In Java, local variables are not, by default, initialized with a certain value (unlike, for example, the field of classes). From the language specification one (§4.12.5) can read the following:
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)).
Therefore, since the variables a and b are not initialized :
for (int l= 0; l<x.length; l++)
{
if (x[l] == 0)
a++ ;
else if (x[l] == 1)
b++ ;
}
the operations a++; and b++; could not produce any meaningful results, anyway. So it is logical for the compiler to notify you about it:
Rand.java:72: variable a might not have been initialized
a++ ;
^
Rand.java:74: variable b might not have been initialized
b++ ;
^
However, one needs to understand that the fact that a++; and b++; could not produce any meaningful results has nothing to do with the reason why the compiler displays an error. But rather because it is explicitly set on the Java language specification that
A local variable (§14.4, §14.14) must be explicitly given a value (...)
To showcase the aforementioned point, let us change a bit your code to:
public static Rand searchCount (int[] x)
{
if(x == null || x.length == 0)
return null;
int a ;
int b ;
...
for (int l= 0; l<x.length; l++)
{
if(l == 0)
a = l;
if(l == 1)
b = l;
}
...
}
So even though the code above can be formally proven to be valid (i.e., the variables a and b will be always assigned with the value 0 and 1, respectively) it is not the compiler job to try to analyze your application's logic, and neither does the rules of local variable initialization rely on that. The compiler checks if the variables a and b are initialized according to the local variable initialization rules, and reacts accordingly (e.g., displaying a compilation error).
You declared them at the start of the method, but you never initialized them. Initializing would be setting them equal to a value, such as:
int a = 0;
int b = 0;
Imagine what happens if x[l] is neither 0 nor 1 in the loop. In that case a and b will never be assigned to and have an undefined value.
You must initialize them both with some value, for example 0.
It's a good practice to initialize the local variables inside the method block before using it. Here is a mistake that a beginner may commit.
public static void main(String[] args){
int a;
int[] arr = {1,2,3,4,5};
for(int i=0; i<arr.length; i++){
a = arr[i];
}
System.out.println(a);
}
You may expect the console will show '5' but instead the compiler will throw 'variable a might not be initialized' error. Though one may think variable a is 'initialized' inside the for loop, the compiler does not think in that way. What if arr.length is 0? The for loop will not be run at all. Hence, the compiler will give variable a might not have been initialized to point out the potential danger and require you to initialize the variable.
To prevent this kind of error, just initialize the variable when you declare it.
int a = 0;
You haven't initialised a and b, only declared them. There is a subtle difference.
int a = 0;
int b = 0;
At least this is for C++, I presume Java is the same concept.
Set variable "a" to some value like this,
a=0;
Declaring and initialzing are both different.
Good Luck

Local variable in java

All code is in Java.
public class TestLocal
{
public static void main(String [] args)
{
int x;
if (args[0] != null)
{ // assume you know this will
// always be true
x = 7; // statement will run
}
int y = x; // the compiler will choke here
}
}
So, my Question is why does the compiler choke here? Does it bypass the if statement (This look quite horrible...) If I initialize x outside the if statement block then the compiler does not complain, as in this code:
public class TestLocal
{
public static void main(String [] args)
{
int x;
x = 7; // compiler is happy now..:)
if (args[0] != null)
{ // assume you know this will
// always be true
// statement will run
}
int y = x; // the compiler not complain here now.
}
}
Why such a horrible behavior from the compiler?
Java requires you to initialize the local variable as a safety measure. It stops you from accidently reading an odd value. If the compiler didn't complain and you were to read the value of x, it could be anything.
Well, the thing is that args[0] might be null, and then x would not be initialized before use. That is why the compiler is complaining at you.
When you don't pass argument then String[] array has nothing and is uninitialized. so the if condition will not be true in this case and even it will throw Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0.. Now assume you have set args[0] to null value at some place in your code then the if(args[0]) != null) will evaluate to false . In that case you are assigning int y= x; where x is uninitialized. And I think you should know compiler takes these things into account. In java you can not use a local variable until it is initialized.
That's why the smart Java compiler gives you compile time error and tell you code properly.
:-). Hope you got it.
According to java Local variables must be initialized before use.
in your case you are trying to initialize it in condition.Conditions never guaranteed to executes(In run time it may executes or may not execute based on the condition) and trying to assign to y variable.
So compiler warns about it.
Because of performance issues among others, Java doesn't initialize automatically local variables. so here:
int x;
x still have an undefined value. Compiler won't allow you to compile the code because you are referring to x in this line:
int y = x;
It works in the second case because you are initializing x before it is referred elsewehere.
Granted, you are initializing x inside the if statement, but obviously it could be the case that your if evaluates to false, so the compiler takes that into account.
int y = x; // the compiler will choke here
Because in case your if block does not execute(when arg[0] ==null) then x will not be initialized. Java compiler mandates the variable to be initialized before they can be used.
You're declaring x as space to hold an integer, but since you didn't give it any integer to hold, it is still null.
The compiler looks at both the true and false paths of your if statement. If arg[0] contains something, then you're fine. Otherwise, when you try to set y = x, x has nothing to give to y and you get an error.

Recursive initializer works when I add "this"?

This fails to compile (with an illegal forward reference error), as one would expect:
class test {
int x = x + 42;
}
But this works:
class test {
int x = this.x + 42;
}
What's going on? What gets assigned in the latter case?
It is too difficult to discover and forbid all accesses to x during x's initialization. For example
int x = that().x; | int x = getX();
|
Test that(){ return this; } | int getX(){ return x; }
The spec stops at "access by simple name" and does not try to be more comprehensive.
In another section, "Definite Assignment", the spec does the similar thing. For example
public class Test
{
static final int y;
static final int z = y; // fail, y is not definitely assigned
static{ y = 1; }
}
public class Test
{
static final int y;
static final int z = Test.y; // pass... because it's not a simple name
static{ y = 1; }
}
Interestingly, "Definite Assignment" specifically mentions that this.x is equivalent to x
(or, for a field, the simple name of the field qualified by this)
this clause could be added to the section quoted by NPE as well.
the usage is via a simple name (or a simple name qualified by this)
But in the end, it is impossible at compile time to analyze all possible usages/accesses to a field.
Summary: Both initializers access a field that's yet to be initialized (and therefore still has the default value of zero). Since this is likely to be a programming error, the language bans some simple forms of such access. However, it does not ban more complex form.
The behaviour is compliant with the JLS, specifically §8.3.2.3. Restrictions on the use of Fields during Initialization
The declaration of a member needs to appear textually before it is used only if the member is an instance (respectively static) field of a class or interface C and all of the following conditions hold:
The usage occurs in an instance (respectively static) variable initializer of C or in an instance (respectively static) initializer of C.
The usage is not on the left hand side of an assignment.
The usage is via a simple name.
C is the innermost class or interface enclosing the usage.
The first example satisfies all four conditions and is therefore invalid. The second example doesn't satisfy the third condition (this.x is not a simple name), and is therefore OK.
The overall sequence of events is as follows:
When an instance of a class is created, all fields are initialized to their type's default values.
Initializers are then run in textual order (from top to bottom).
Thus if an initializer refers to a field that appears later in the class definition (or to the field itself), it would see the default value of that other field. This is likely to be be a programming error and is therefore explicitly forbidden by §8.3.2.3.
If you circumvent §8.3.2.3 by, for example, using this. to forward-refer to a field, you'll see the default value (zero for int). Thus the following is well-defined and is guaranteed to set x to 42:
class test {
int x = this.x + 42;
}
In the first case compiler tries to evaluate expression 'x + 42' but fails because x is not initialized.
In the second case expression 'this.x + 42' is evaluated at runtime (because of 'this' keyword), when x is already initialized and has value 0.

What is called a forward reference in Java?

I have been through this question on legality of forward references but not clear as to what is meant by forward references in Java language . Can someone please explain with the help of an example ?
This is specifically a compilation error. And its all about ordering of class variable declarations. Let's use some code for illustrative purposes:
public class ForwardReference {
public ForwardReference() {
super();
}
public ForwardReference echoReference() {
return this;
}
public void testLegalForwardReference() {
// Illustration: Legal
this.x = 5;
}
private int x = 0;
// Illustration: Illegal
private ForwardReference b = a.reference();
private ForwardReference a = new ForwardReference();
}
As you can see, Java allows you to reference a class variable in a class method, even if the declaration of the variable comes after the method. This is an example of a (legal) forward reference, and support for this is built into the Java compiler.
What you cannot do though, is declare a class variable 'a' that depends on another class variable 'b' that has not been declared yet. Dependent class variable declarations must appear in reverse order of their dependency.
On a tangent, Most, if not all IDE's will warn you if your code contains illegal reference errors.
Illegal forward references are covered in section 8.3.2.3 of the JLS.
It's basically just the order that things are read by the compiler, if you have
int c = 3
int a = b;
int b = 5;
the compiler will read it from top to bottom, so it will se the first line, which declares a variable 'c', and assigns it to 3, and that is fine, then it will encounter the second line, which declares a variable 'a', and then tries to assign it to 'b'.
But now, the compiler has a problem: What is this 'b' thing? It has only yet learned about 'c', and just recently 'a', but it has no knowledge anything called 'b', since to the compiler, it has not yet been declared. So then, since the compiler can't handle all the confusion, it stops, and leaves you to figure what you have done to anger it.
So, the forward reference part would be a reference to something that does not yet exist. Forward in time perhaps..
In simple terms it means referencing (accessing a variable, calling a function) that is further down in the code file.
static int x=getY();
static int y=5;
static int getY() { return y; }
x's value is set to the result of getY()
getY() is called before y's value is set to 5
x's value is therefore 0 (default integer)
y's value is 5
public class AnyCode {
void print() {
System.out.println("Value of j - " + j); // legal
System.out.println("Value of i - " + i); // legal
}
// CASE - 1
int k = i; // illegal
int i;
// CASE - 2
int l = j; // legal
static int m = j; // illegal
static int j;
// CASE - 3
A aObj = bObj; // illegal
B bObj = new B();
public static void main(String[] args) {
/*
Note :- here anyCode act as a local variable and get space on stack
whereas the object it is referring to is present on heap. And you
cannot forward reference a local variable.
*/
anyCode.print(); // 'Cannot find symbol' error
AnyCode anyCode = new AnyCode();
}
}
class A {
}
class B {
}
*********Refer CASE - 1*********
Forward referencing instance variable is not allowed as compiler is not sure of the type of value we are forward referencing or it might even be possible that no such variable exist.
Consider an example :-
int a = b;
boolean b = false;
If forward referencing is allowed in above case then it might create a havoc.
int a = b; // What is b? is it a primitive variable or a value or a object reference
in the above example i have decided not to declare b and now if such assignment were allowed by java, then it will be a nightmare.
**********Refer CASE - 2*********
Static variables are loaded before instance variables and hence forward referencing static variables and assigning them to instance variable is perfectly fine

In what order are initializer block and variable definitions and etc. executed? (in java)

I have problem understanding the order in which initialization happens. this is the order I assumed:
*Once per
1. Static variable declaration
2. Static block
*Once per object
3. variable declaration
4. initialization block
5. constructor
but according to this code I am obviously wrong:
class SomethingWrongWithMe
{
{
b=0; //no. no error here.
int a = b; //Error: Cannot reference a field before it is defined.
}
int b = 0;
}
And the error would disappear if I do this:
class SomethingWrongWithMe
{
int b = 0;
{
b=0;
int a = b; //The error is gone.
}
}
I can't figure out why isn't there an error on
b=0;
The Java Language Specification (section 8.3.2.3) says you can use a variable on the left hand side of an expression, i.e. assign to it, before it is declared, but you cannot use it on the right hand side.
All variables are initialized to their default values, then explicit initializers and anonymous blocks are run in the order they are found in the source file. Finally the constructor is called.
Statics are only run once on the first use of a class.
The compile error appears to be a rule of Java rather than something that necessarily makes sense in every case.
Variable definitions are not done "before" blocks. They are both done at the same time, in the order that they are defined
class SomethingWrongWithMe {
{
b = debug("block 1");
}
int b = debug("define");
{
b = debug("block 2");
}
private int debug(String str) {
System.out.println(str);
return 0;
}
}
Output
block 1
define
block 2
First of all, your assumptions are more or less correct, except for the fact that declarations (with initialization, such as int b = 0) and instance initializer blocks are executed in the order they are written.
int b = 0; // executed first
{
b = 1; // executed second
}
int a = b; // executed third
Also note that the declaration i.e. int b is not executed. The declaration just declares the existence of the variable.
As for the error you got (or, rather the error you didn't get) I agree that it looks strange. I assume that the compiler deals with referencing a variable in an expression and assigning a value to it in different ways. When writing to a variable in an instance initializer, it just checks that the variable is there, while when reading from it, it requires it to be declared above the instance initializer block. I'll see if I can find a reference for that in the JLS.

Categories