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.
Related
Here is some code that calls static method A.f() on class that is not initialized yet.
Can someone explain behavior of this code in terms of JLS?
class A {
final static Object b = new B();
final static int S1 = 1;
final static Integer S2 = 2;
static void f() {
System.out.println(S1);
System.out.println(S2);
}
}
class B {
static {
A.f();
}
}
public class App
{
public static void main( String[] args )
{
A.f();
}
}
Output:
1
null
1
2
A.f() in App.main() triggers initialization of class A.
All constant variables are initialized. The only constant variable is S1, which now is 1.
Then, the other static fields are initialized in textual order. b is the first field, which triggers initialization of class B, which in turn calls A.f(). S2 is simply null because it is not initialized yet. Initialization of b is now complete. Last but not least, S2 is initialized to the Integer object 2.
S2 is not a constant variable because it is not of the primitive type int but of the reference type Integer. S2 = 2; is an auto-boxing shorthand for S2 = Integer.valueOf(2);.
If a declarator in a field declaration has a variable initializer, then the declarator has the semantics of an assignment (§15.26) to the declared variable.
[…]
Note that static fields that are constant variables (§4.12.4) are initialized before other static fields (§12.4.2). This also applies in interfaces (§9.3.1). Such fields will never be observed to have their default initial values (§4.12.5), even by devious programs.
8.3.2. Field Initialization
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28). Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9), and definite assignment (§16 (Definite Assignment)).
4.12.4. final Variables
A constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:
Literals of primitive type and literals of type String
[…]
15.28. Constant Expressions
For each class or interface C, there is a unique initialization lock LC. The mapping from C to LC is left to the discretion of the Java Virtual Machine implementation. The procedure for initializing C is then as follows:
[…]
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.
12.4.2. Detailed Initialization Procedure
Every variable in a program must have a value before its value is used:
Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2):
[…]
For all reference types (§4.3), the default value is null.
4.12.5. Initial Values of Variables
It seems that this issue doesn't belong to JLS, but we have deal with JVMS.
On Linking stage before resolution process there is Preparation substage, which involves:
creating the static fields for a class or interface and initializing
such fields to their default values
and more:
explicit initializers for static fields are executed as part of
initialization (§5.5), not preparation
while initialization includes:
The execution of any one of the Java Virtual Machine instructions new
Initializing of primitive types includes writing their initial value. For reference type fields their default value is null because before Resolution substage jvm doesn't "know" which class is associated to apropriate symbolic reference name of a class.
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.
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
I'm reading up on Java and I am scratching my head as to why System.out.println("a: " + a); does not yield a compilation error. Where is a ever initialized?
public class localVariableEx {
public static int a;
public static void main(String[] args) {
int b;
System.out.println("a: " + a);
System.out.println("b: " + b); //Compilation error
}
}
The relevant rules of this are described in the JLS § 4.12.5 Initial Values of Variables (emphasis mine):
Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10): [...]
[...]
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 by the compiler using the rules for definite assignment (§16).
So while instance variables (such as a) automatically get a default value, local variables (such as b) don't get one and must not be used unless the compiler can verify that a value has been assigned to them.
b is a variable defined in the method scope only, so the compiler can know that no one initialized it before, but a is a public variable that might be initialized somewhere else.
a is of a primitive type int which will get initialized immediately, which means:
Static class members: get init'ed when the class is loaded (most of the time, when the before main(), but it depends on when the class is loaded).
class S {
static int a;
}
Non-Static class members: get init'ed when the object is. (most of the time after new, but there're other, more advanced, methods to new an object).
class S {
int a;
}
Local variables: should be init'ed in the method's scope before first use.
class S {
void foo() {
int b = 0;
}
}
edited after being corrected...
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