I was working on a problem to store reference of two classes within each other
For Example:
class A {
B b;
A(B b){
this.b = b;}
}
class B {
A a;
B(A a){
this.a = a;}
}
public static void main(String...s){
A a = new A(new B(null));
a.b.a = a;
}
Now if instead of above initialisation, if I use below statement:
A a = new A(new B(a));
I got below error which is quite obvious:
Main.java:19: error: variable a might not have been initialised
A a = new A(new B(a));
But if I try the same on JShell, it works just fine (Just to be extra sure that variable a
has never been initialized, I checked for variable a
just before executing the statement which confirms that it was not initialized before:
May be I am missing something here, but can some one please help me to understand why there are two different behaviours of the same statement being executed in JAVA.
A simple way to understand this problem is that below statement is allowed in Jshell
but not in normal program:
var somevar = somevar;
The statement A a = new A(new B(a));
is not the declaration of a local variable.
But first, the issue you're describing can be simplified to:
jshell> int a = a;
a ==> 0
Now, how did that work?
Well, as Snippets of JEP 222 says it:
In JShell, a "variable" is a storage location and has an associated type. A variable is created explicitly with a FieldDeclaration snippet:
int a = 42;
or implicitly by an expression (see below). Variables have a small amount of field semantics/syntax (for example, the volatile
modifier is allowed). However, variables have no user-visible class enclosing them and will be generally viewed and used like local variables.
So, they behave a little like fields and a little like local variables.
Like a field, but unlike a local variable, a declaration without initializer will assign a default value, e.g.
jshell> int b;
b ==> 0
But, back to int a = a;
. Section State of JEP 222 says:
The JShell state is held in an instance of JShell. A snippet is evaluated in a JShell with the eval(...)
method, producing an error, declaring code, or executing a statement or expression. In the case of a variable with an initializer, both declaration and execution occur.
So, the declaration of the variable, and the execution of the initializer, are two separate actions.
This means that when the initializer is executed, the variable has already been declared, and has already been assigned the default value.
In effect, int a = a;
is evaluated as:
jshell> int a;
a ==> 0
jshell> a = a;
a ==> 0
This is how the jshell REPL is designed to work. It is not a bug.
Though I totally agree with @Andreas answer above that this is expected with the way initialisation is currently working in JShell, I also have the same view as @Dawood that JShell should work to normal compiler as close as possible, otherwise it can sometime be uncertain and hence unsafe to use.
For this particular scenario, I raised an issue with Oracle and it has now been accepted as an official bug. You can track more about this bug here:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8200567
Hope that this will be resolved soon in the upcoming releases of JShell.