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.
Related
This is meant to be a canonical question and answer for similar questions where the issue is a result of shadowing.
I've defined two fields in my class, one of a reference type and one of a primitive type. In the class' constructor, I try to initialize them to some custom values.
When I later query for those fields' values, they come back with Java's default values for them, null for the reference type and 0 for the primitive type. Why is this happening?
Here's a reproducible example:
public class Sample {
public static void main(String[] args) throws Exception {
StringArray array = new StringArray();
System.out.println(array.getCapacity()); // prints 0
System.out.println(array.getElements()); // prints null
}
}
class StringArray {
private String[] elements;
private int capacity;
public StringArray() {
int capacity = 10;
String[] elements;
elements = new String[capacity];
}
public int getCapacity() {
return capacity;
}
public String[] getElements() {
return elements;
}
}
I expected getCapacity() to return the value 10 and getElements() to return a properly initialized array instance.
Entities (packages, types, methods, variables, etc.) defined in a Java program have names. These are used to refer to those entities in other parts of a program.
The Java language defines a scope for each name
The scope of a declaration is the region of the program within which
the entity declared by the declaration can be referred to using a
simple name, provided it is visible (§6.4.1).
In other words, scope is a compile time concept that determines where a name can be used to refer to some program entity.
The program you've posted has multiple declarations. Let's start with
private String[] elements;
private int capacity;
These are field declarations, also called instance variables, ie. a type of member declared in a class body. The Java Language Specification states
The scope of a declaration of a member m declared in or inherited by a
class type C (§8.1.6) is the entire body of C, including any nested
type declarations.
This means you can use the names elements and capacity within the body of StringArray to refer to those fields.
The two first statements in your constructor body
public StringArray() {
int capacity = 10;
String[] elements;
elements = new String[capacity];
}
are actually local variable declaration statements
A local variable declaration statement declares one or more local variable names.
Those two statements introduce two new names in your program. It just so happens that those names are the same as your fields'. In your example, the local variable declaration for capacity also contains an initializer which initializes that local variable, not the field of the same name. Your field named capacity is initialized to the default value for its type, ie. the value 0.
The case for elements is a little different. The local variable declaration statement introduces a new name, but what about the assignment expression?
elements = new String[capacity];
What entity is elements referring to?
The rules of scope state
The scope of a local variable declaration in a block (§14.4) is the
rest of the block in which the declaration appears, starting with its
own initializer and including any further declarators to the right in
the local variable declaration statement.
The block, in this case, is the constructor body. But the constructor body is part of the body of StringArray, which means field names are also in scope. So how does Java determine what you're referring to?
Java introduces the concept of Shadowing to disambiguate.
Some declarations may be shadowed in part of their scope by another
declaration of the same name, in which case a simple name cannot be
used to refer to the declared entity.
(a simple name being a single identifier, eg. elements.)
The documentation also states
A declaration d of a local variable or exception parameter named n
shadows, throughout the scope of d, (a) the declarations of any other
fields named n that are in scope at the point where d occurs, and (b)
the declarations of any other variables named n that are in scope at
the point where d occurs but are not declared in the innermost class
in which d is declared.
This means that the local variable named elements takes priority over the field named elements. The expression
elements = new String[capacity];
is therefore initializing the local variable, not the field. The field is initialized to the default value for its type, ie. the value null.
Inside your methods getCapacity and getElements, the names you use in the in their respective return statements refer to the fields since their declarations are the only ones in scope at that particular point in the program. Since the fields were initialized to 0 and null, those are the values returned.
The solution is to get rid of the local variable declarations altogether and therefore have the names refer to the instance variables, as you originally wanted. For example
public StringArray() {
capacity = 10;
elements = new String[capacity];
}
Shadowing with constructor parameters
Similar to the situation described above, you may have formal (constructor or method) parameters shadowing fields with the same name. For example
public StringArray(int capacity) {
capacity = 10;
}
Shadowing rules state
A declaration d of a field or formal parameter named n shadows,
throughout the scope of d, the declarations of any other variables
named n that are in scope at the point where d occurs.
In the example above, the declaration of the constructor parameter capacity shadows the declaration of the instance variable also named capacity. It's therefore impossible to refer to the instance variable with its simple name. In such cases, we need to refer to it with its qualified name.
A qualified name consists of a name, a "." token, and an identifier.
In this case, we can use the primary expression this as part of a field access expression to refer to the instance variable. For example
public StringArray(int capacity) {
this.capacity = 10; // to initialize the field with the value 10
// or
this.capacity = capacity; // to initialize the field with the value of the constructor argument
}
There are Shadowing rules for every kind of variable, method, and type.
My recommendation is that you use unique names wherever possible so as to avoid the behavior altogether.
int capacity = 10; in your constructor is declaring an local variable capacity which shadows the field of the class.
The remedy is to drop the int:
capacity = 10;
This will change the field value. Ditto for the other field in the class.
Didn't your IDE warn you of this shadowing?
There are two parts to using variables in java/c/c++. One is to declare the variable and the other is to use the variable (whether assigning a value or using it in a calculation).
When you declare a variable you must declare its type. So you would use
int x; // to declare the variable
x = 7; // to set its value
You do not have to re-declare a variable when using it:
int x;
int x = 7;
if the variable is in the same scope you will get a compiler error; however, as you are finding out, if the variable is in a different scope you will mask the first declaration.
Another widely accepted convention is to have some prefix (or suffix - whatever you prefer) added to class members to distinguish them from local variables.
For example class members with m_ prefix:
class StringArray {
private String[] m_elements;
private int m_capacity;
public StringArray(int capacity) {
m_capacity = capacity;
m_elements = new String[capacity];
}
public int getCapacity() {
return m_capacity;
}
public String[] getElements() {
return m_elements;
}
}
Most IDEs have already available support for this notation, below is for Eclipse
After reading the question, I know the differences between declaration and definition. So does it mean definition equals declaration plus initialization?
Declaration
Declaration, generally, refers to the introduction of a new name in the program. For example, you can declare a new function by describing it's "signature":
void xyz();
or declare an incomplete type:
class klass;
struct ztruct;
and last but not least, to declare an object:
int x;
It is described, in the C++ standard, at §3.1/1 as:
A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations.
Definition
A definition is a definition of a previously declared name (or it can be both definition and declaration). For example:
int x;
void xyz() {...}
class klass {...};
struct ztruct {...};
enum { x, y, z };
Specifically the C++ standard defines it, at §3.1/1, as:
A declaration is a definition unless it declares a function without specifying the function’s body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a function- body, it declares a static data member in a class definition (9.2, 9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), it is a template-parameter (14.1), it is a parameter-declaration (8.3.5) in a function declarator that is not the declarator of a function-definition, or it is a typedef declaration (7.1.3), an alias-declaration (7.1.3), a using-declaration (7.3.3), a static_assert-declaration (Clause 7), an attribute- declaration (Clause 7), an empty-declaration (Clause 7), or a using-directive (7.3.4).
Initialization
Initialization refers to the "assignment" of a value, at construction time. For a generic object of type T, it's often in the form:
T x = i;
but in C++ it can be:
T x(i);
or even:
T x {i};
with C++11.
Conclusion
So does it mean definition equals declaration plus initialization?
It depends. On what you are talking about. If you are talking about an object, for example:
int x;
This is a definition without initialization. The following, instead, is a definition with initialization:
int x = 0;
In certain context, it doesn't make sense to talk about "initialization", "definition" and "declaration". If you are talking about a function, for example, initialization does not mean much.
So, the answer is no: definition does not automatically mean declaration plus initialization.
Declaration says "this thing exists somewhere":
int foo(); // function
extern int bar; // variable
struct T
{
static int baz; // static member variable
};
Definition says "this thing exists here; make memory for it":
int foo() {} // function
int bar; // variable
int T::baz; // static member variable
Initialisation is optional at the point of definition for objects, and says "here is the initial value for this thing":
int bar = 0; // variable
int T::baz = 42; // static member variable
Sometimes it's possible at the point of declaration instead:
struct T
{
static int baz = 42;
};
…but that's getting into more complex features.
For C, at least, per C11 6.7.5:
A declaration specifies the interpretation and attributes of a set of
identifiers. A definition of an identifier is a declaration for that
identifier that:
for an object, causes storage to be reserved for that object;
for a function, includes the function body;
for an enumeration constant, is the (only) declaration of the identifier;
for a typedef name, is the first (or only) declaration of the identifier.
Per C11 6.7.9.8-10:
An initializer specifies the initial value stored in an object ... if
an object that has automatic storage is not initialized explicitly,
its value is indeterminate.
So, broadly speaking, a declaration introduces an identifier and provides information about it. For a variable, a definition is a declaration which allocates storage for that variable.
Initialization is the specification of the initial value to be stored in an object, which is not necessarily the same as the first time you explicitly assign a value to it. A variable has a value when you define it, whether or not you explicitly give it a value. If you don't explicitly give it a value, and the variable has automatic storage, it will have an initial value, but that value will be indeterminate. If it has static storage, it will be initialized implicitly depending on the type (e.g. pointer types get initialized to null pointers, arithmetic types get initialized to zero, and so on).
So, if you define an automatic variable without specifying an initial value for it, such as:
int myfunc(void) {
int myvar;
...
You are defining it (and therefore also declaring it, since definitions are declarations), but not initializing it. Therefore, definition does not equal declaration plus initialization.
"So does it mean definition equals declaration plus initialization."
Not necessarily, your declaration might be without any variable being initialized like:
void helloWorld(); //declaration or Prototype.
void helloWorld()
{
std::cout << "Hello World\n";
}
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.
Java assigns default values to instance variables using default constructor. But if we define our own constructor then how does java give default values (because when we write our constructor then, then default constructor is not added).
Java assigns default values to instance variables using default constructor.
No, not really. It automatically assigns default values to all members prior to executing any constructor.
But if we define our own constructor then how does java give default values (because when we write our constructor then, then default constructor is not added).
It still assigns default values to all members.
class Test {
int i;
Object ref;
Test() {
System.out.println(i);
System.out.println(ref);
}
public static void main(String[] args) {
new Test();
}
}
Output:
0
null
Here's what happens when an object is created using new; see JLS 12.5
Space for the object is allocated on the heap, and the object's size and class are associated with the object.
All fields of the object are set to the default value; i.e. null or reference types, and zero or false for primitive types.
The argument expressions for the super or this arguments (if any) are evaluated, and the constructor chain is called recursively.
If they haven't already been evaluated (via this chaining), any instance field initializers and any initializer blocks for this class are evaluated/executed in order.
The rest of the constructor body (if any) is executed to complete the object initialization.
The same procedure is used whether there is an explicitly declared constructor, or a default constructor. A default constructor is simply a short-hand for a constructor that just calls super().
So ....
Java assigns default values to instance variables using default constructor.
Actually, the default values are assigned before that, and (indeed) initializers, etc are executed before an (empty) default constructor is executed.
The default constructor is not responsible for doing default initialization. So the fact that it is not invoked doesn't matter.
aioobe's answer is right. I just want to say why/how it is that way:
Independent of whether you have a default or own constructors, the java compiler constructs instance initialization "methods" for each one (called void <init>, with the constructor's parameters - if you want to look into decompiled byte-code).
The structure of each <init> "method" is:
An invocation of another constructor
Instance variable initializers (your instance variable initializers, as well as instance initializers)
The constructor body.
Further details can be found in the JLS and JVMS, as well as in this nice introduction.
public class DefaultValue {
private boolean BOOLEAN;
private byte BYTE;
private short SHORT;
private int INT ;
private long LONG;
private float FLOAT;
private double DOUBLE;
private char CHAR;
private Object OBJECT;
public DefaultValue() {
System.out.println("I did nothing!");
}
public static void main(String args[]) {
DefaultValue dv = new DefaultValue();
System.out.println(dv.BOOLEAN);
System.out.println(dv.BYTE);
System.out.println(dv.SHORT);
System.out.println(dv.INT);
System.out.println(dv.LONG);
System.out.println(dv.FLOAT);
System.out.println(dv.DOUBLE);
System.out.println(dv.CHAR);
System.out.println(dv.OBJECT);
}
}
I rewrite the default constructor. Though I did nothing in the constructor, the variables are assigned.
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