I know the Operator Precedence list, but I just cannot figure out what is the execution precedence in this code in "LINE 1". What Object is created before? For example: the My String or the new Precedence()? How can we apply the Operator Precedence rule in this example?
public class Precedence {
public String s;
public static void main (String ... args){
String a = new Precedence().s="My String"; // LINE 1
System.out.println(a);
}
}
OUTPUT:
My String
This
String a = new Precedence().s="My String"; // LINE 1
is a local variable declaration statement with an initialization expression.
Every time it is executed, the declarators are processed in order from
left to right. If a declarator has an initializer, the initializer is
evaluated and its value is assigned to the variable.
a is the declarator. It's evaluated to produce a variable (itself). Then the initialization expression is evaluated.
This
new Precedence().s = "My String";
is an assignment expression. The left hand side of the operator is evaluated first to produce a variable, so new Precedence() is evaluated first, instantiates the class Precedence, producing a reference to an object. Then the right hand side of the assignment is evaluated, the String literal "My String", so a reference to a String object is produced. Then the assignment happens assigning the reference to the String object to the variable s of the object referenced by the value returned by the new instance creation expression.
Finally, since
At run time, the result of the assignment expression is the value of
the variable after the assignment has occurred.
The value that was assigned to the field s of the Precedence object is also assigned to the variable a.
Here's the bytecode:
public static transient varargs main([Ljava/lang/String;)V
L0
LINENUMBER 8 L0
NEW Precedence
DUP
INVOKESPECIAL Precedence.<init> ()V
LDC "My String"
DUP_X1
PUTFIELD Precedence.s : Ljava/lang/String;
ASTORE 1
This shows the following execution order:
Create Precedence object.
Assign My String constant to Precedence.s.
Assign it also to a.
There is tool javap, dissasembler, which will show you bytecode and from there you can conclude what is order of execution. It will output comments.
$ /usr/lib/jvm/java-7-oracle/bin/javap -c Precedence.class
Compiled from "Precedence.java"
public class Precedence {
public java.lang.String s;
public Precedence();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String...);
Code:
0: new #2 // class Precedence
3: dup
4: invokespecial #3 // Method "<init>":()V
7: ldc #4 // String My String
9: dup_x1
10: putfield #5 // Field s:Ljava/lang/String;
13: astore_1
14: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
17: aload_1
18: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
21: return
}
javap is part of JDK, path is on Linux, switch -c is Disassemble the code. Here is definition of instruction ldc, it is not obvious what it does
push a constant #index from a constant pool (String, int or float) onto the stack
Related
I've asked several questions regarding the subject, but it seems like every time I get an answer, I have more questions.
This question is continuation of my other question: Initialization in polymorphism of variables
Anyways, consider the following example.
class A{ //1
int a = 1; //2
}
i heard this conceptually looks like,
class A { //1
int a = 0; //2
A() { //3
super(); //4
a = 1; //5
}
From what I understand, this is because every time an object is created, instance objects are initialized to its default values.
If I put initialization block say,
System.out.print(i);
right below line 2 for both examples, top will print 1 and bottom will print 0. As far as I know, initialization block is executed before constructor. So is this only conceptual representation of constructors only? Or does the code actually change as such when the default constructor is called? Can someone clarify this for me?
Why does it behave this way? In my other question, it seemed to only cause confusion as to which variable is called. Can't instance variable just be declared a=1 and gets used throughout the class? Shouldn't that make it simpler?
As you said, the equivalence between the two classes in your question is only conceptual.
In fact, if an non-static data field has an initialization value, it is initialized before calling the constructor. The initialization block is copied by the compiler to the beginning of every constructor (after the super line), so it is executed after the initialization of the field and before the constructor code itself.
Your description of how int a = 1 gets converted to a constructor is correct, but it is not the whole story.
If, in addition to a, there are other instance fields with initializers, all of their initializers are collected into a single block that runs as part of constructors
If, in addition to field initialization you have general-purpose initializer blocks, their content gets collected into that same block, along with field initializers.
For example, if you have
class A {
{
System.out.println(a);
}
int a = 1;
{
System.out.println(a);
System.out.println(b);
}
int b = 2;
{
System.out.println(b);
}
public A() {
// Code of A
}
}
then the code block prior to Code of A looks like this:
System.out.println(a);
a = 1;
System.out.println(a);
System.out.println(b);
b = 2;
System.out.println(b);
// Code of A
It should be clear now why zero is printed in the initialization block prior to int a = 1 in the block preceding the initializer: initialization blocks are not treated separately from field initializers, their code gets mixed together in the same order that they appear in the source code.
The difference between your example is the order of operations. In your first example, with the initializer block where you said, the order is:
Assign 1 to a (in the declaration)
Output a (in the initializer block)
...but in your example example, it's
Assign 0 (the default value) to a (effectively in the declaration)
Output a (in the initialization block)
Assign 1 to a (in the constructor)
The key to understanding instance initialization for me is this: Instance initialization code is literally copied into the constructors — all of them, including the default one — by the compiler. It's copied in source code order, and it's before anything in the constructor (including super).
Here's a more complete example. Consider this class:
class Example {
// Instance field with initializer
private int i = 5;
// Instance initialization block
{
System.out.println(this.i);
}
// constructor 1
Example() {
System.out.println(this.i * 2);
}
// constructor 2
Example(int _i) {
this.i = _i;
System.out.println(this.i * 3);
}
}
That's compiled into bytecode exactly as though it were this:
class Example {
// Instance field
private int i;
// constructor 1
Example() {
// begin copied code
this.i = 5;
System.out.println(this.i);
// end copied code
System.out.println(i * 2);
}
// constructor 2
Example(int _i) {
// begin copied code
this.i = 5;
System.out.println(this.i);
// end copied code
this.i = _i;
System.out.println(this.i * 3);
}
}
In both cases above, Oracle's Java 8 outputs the exact same bytecode (as viewed by using javap -c Example after compiling):
Compiled from "Example.java"
class Example {
Example();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: aload_0
5: iconst_5
6: putfield #2 // Field i:I
9: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_0
13: getfield #2 // Field i:I
16: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
19: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
22: aload_0
23: getfield #2 // Field i:I
26: iconst_2
27: imul
28: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
31: return
Example(int);
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: aload_0
5: iconst_5
6: putfield #2 // Field i:I
9: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_0
13: getfield #2 // Field i:I
16: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
19: aload_0
20: iload_1
21: putfield #2 // Field i:I
24: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
27: aload_0
28: getfield #2 // Field i:I
31: iconst_3
32: imul
33: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
36: return
}
Instance variables are immediately available with the default variable if not otherwise set: Objects are set to null and primitive types to 0, false etc.
You have 3 options to set the value of an instance variable in Java:
1) Declare and instantiate immediately
class A {
int i = 1;
}
2) Instantiate it in a instance initializer block
class A {
int a; // it is default value 0 at this point
{ a = 1; } //instance initializer block
}
3) Instantiate it in the constructor
class A{
int a; // it is default value 0 at this point
A() {
a = 1;
}
}
During the instantiation of the A object, Java will
first instantiate the variable a to its default if not done by the user,
then it will go through any instance initializer block in the order they appear, and lastly
it will enter the constructor.
This question already has answers here:
Are enum names interned in Java?
(4 answers)
Closed 1 year ago.
Can anyone explain why toString() and name() are referencing the same String? when I used == to compare them with a String literal they all pass! How does enum name work with String pool from JVM?
static enum User
{
BASIC, PREMIUM;
}
System.out.println("BASIC" == User.BASIC.toString()); // true
System.out.println("BASIC" == User.BASIC.name()); // true
Well, Enum.name() and Enum.toString() return the same private field, so the references are always going to be the same. Both calls return name and name == name is always going to be true.
To better answer your question, however, the JVM's internal string pool stores only one copy of distinct strings. You're only requesting one distinct string, "BASIC", and since Strings are immutable it is stored only once so .toString() and .name() would likely return the same reference even if those calls were returning different fields.
EDIT:
Also, string literals (strings in quotes in source code) are all gathered up at compile time and any duplicates are all mapped to the same reference. So if, for instance, you have places all over your source code where you're using the literal "Hello I am a string literal", then that exact string is only stored one time and, since strings are immutable and will never change, every place that used that literal in your source code now uses a reference to the single place where it's stored in the JVM String pool. This is because, if possible, it's obviously better to not make a bunch of copies of the same thing. That's a vast oversimplification but you get the idea.
Compiling your enum class and disassembling with javap -verbose gives this (partial) output:
final class User extends java.lang.Enum<User>
minor version: 0
major version: 52
flags: ACC_FINAL, ACC_SUPER, ACC_ENUM
Constant pool:
#7 = String #13 // BASIC
#9 = Fieldref #4.#38 // User.BASIC:LUser;
#10 = String #15 // PREMIUM
#11 = Fieldref #4.#39 // User.PREMIUM:LUser;
#13 = Utf8 BASIC
#15 = Utf8 PREMIUM
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=4, locals=0, args_size=0
0: new #4 // class User
3: dup
4: ldc #7 // String BASIC
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field BASIC:LUser;
13: new #4 // class User
16: dup
17: ldc #10 // String PREMIUM
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field PREMIUM:LUser;
26: iconst_2
27: anewarray #4 // class User
30: dup
31: iconst_0
32: getstatic #9 // Field BASIC:LUser;
35: aastore
36: dup
37: iconst_1
38: getstatic #11 // Field PREMIUM:LUser;
41: aastore
42: putstatic #1 // Field $VALUES:[LUser;
45: return
LineNumberTable:
line 1: 0
By the time that an enum is compiled, it's just an ordinary Java .class file, whose only distinguishing features at runtime are the fact that it extends Enum and has the ACC_ENUM flag set; everything else is just plain bytecode.
To set up the enum constants, including their names, the compiler could theoretically use complicated reflection to derive the names from the value names, but instead it's far simpler and just as effective to inline the names as string constants. The static initializer loops through the names, calling the private constructor to instantiate the value instances and assign them to the private $VALUES array.
As these strings are in the constant pool, the usual deduplication logic then applies. toString() returns the same object because its default implementation is simply to return name.
because the enum class in java looks like this:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
private final String name;
public final String name() {
return name;
}
private final int ordinal;
public final int ordinal() {
return ordinal;
}
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public String toString() {
return name;
}
in general you should compare enums with == but if you want to use the name pls use .equals()
The JVM implementation is reusing the same String constant, because they're both loaded in the same class at the same time. That is an optimization made by the specific JVM implementation you're using (and probably most of the existing ones). If you did this, you would get false.
String s = (new StringBuilder("BAS")).append("IC").toString();
System.out.println(s == User.BASIC.toString());
This is because the String reference s is created at runtime.
You would also likely get false if they're loaded from different classes.
The below text is from jls http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
Even then, there are a number of complications. If a final field is
initialized to a compile-time constant expression (§15.28) in the
field declaration, changes to the final field may not be observed,
since uses of that final field are replaced at compile time with the
value of the constant expression.
Can anyone please give me better explanation for the above. I couldn't understand the statement "changes to the final field may not be observed". May with the help of example.
I couldn't understand the statement changes to the final field may not be observed
It tells that , if a final variable is declared as compile time constant then any change made in the final variable using reflection API further in program will not be visible to the program during execution.
For example consider the code given below:
import java.lang.reflect.*;
class ChangeFinal
{
private final int x = 20;//compile time constant
public static void change(ChangeFinal cf)
{
try
{
Class clazz = ChangeFinal.class;
Field field = clazz.getDeclaredField("x");
field.setAccessible(true);
field.set(cf , 190);//changed x to 190 for object cf
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String[] args)
{
ChangeFinal cf = new ChangeFinal();
System.out.println(cf.x);//prints 20
change(cf);
System.out.println(cf.x);//prints 20
}
}
The Output of the above code is:
20
20
WHY?
The answer lies in the output provided by javap -c command for public static void main:
public static void main(java.lang.String[]);
Code:
0: new #3; //class ChangeFinal
3: dup
4: invokespecial #11; //Method "<init>":()V
7: astore_1
8: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Cla
ss;
15: pop
16: bipush 20
18: invokevirtual #14; //Method java/io/PrintStream.println:(I)V
21: aload_1
22: invokestatic #15; //Method change:(LChangeFinal;)V
25: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_1
29: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Cla
ss;
32: pop
33: bipush 20
35: invokevirtual #14; //Method java/io/PrintStream.println:(I)V
38: return
}
At line 16 (before changeFinal method is called)the value of cf.x is hardcoded to 20 . And at line 33 (after changeFinal method is called) the value of cf.x is again hardcoded to 20. Therefore , Although the change in the value of final variable x is done successfully by reflection API during execution, but because of x being a compile time constant it is showing its constant value 20.
It means if in a class you have this:
public class Foo {
public final boolean fooBoolean = true; // true is a constant expression
public final int fooInt = 5; // 5 is a constant expression
}
At compile time any reference to Foo.fooBoolean may be replaced with true, and references to Foo.fooInt may be replaced by 5. If at runtime you later change either of those final fields via reflection, the code referencing it (as it was written) may never see it.
It is quite possible for a Java program to observe a final field having two different values at different times, even without reflection, without recompiling multiple versions of the class, and without anything along those lines. Consider the class below:
class X {
static final int x = getX();
static int getX() {
System.out.println("X.x is now " + X.x);
return 1;
}
public static void main(String[] args) {
System.out.println("X.x is now " + X.x);
}
}
Output:
X.x is now 0
X.x is now 1
This happens because some of the code (the first println) is executed before the field's value is assigned, so that code observes the field's default initial value of 0. The field has a default initial value before it is assigned, even though it is final, because it is not a constant field. The text you quoted from the JLS says this kind of thing cannot happen if the field is declared as a constant.
This question already has answers here:
Uninitialized class members in Java do not issue any compiler errors. local variables however do. Why?
(5 answers)
Closed 6 years ago.
Why do variables declared in a class have default values, but the variables declared inside methods, said to be "local variables", don't have default values in Java?
For example
class abc
{
int a;
public static void main(String ss[])
{
int b;
abc aa=new abc();
System.out.println(aa.a);
System.out.println(b);
}
}
In this above example variable a has default value of 0 but variable b gives error that it might not have been initialized.
All member variable have to load into heap so they have to initialized with default values when an instance of class is created. In case of local variables, they don't get loaded into heap they are stored in stack until they are being used before java 7, so we need to explicitly initialize them.
Now the "Java Hotspot Server Compiler" performs "escape analysis" and decides to allocate some variables on the stack instead of the heap.
Local variables Initialization
Variables declared in methods and in blocks are called local variables. Local variable are not initialized when they are created at method invocation. Therefore, a local variable must be initialized explicitly before being used. Otherwise the compiler will flag it as error when the containing method or block is executed.
Example:
public class SomeClassName{
public static void main(String args[]){
int total;
System.out.println("The incremented total is " + total + 3); //(1)
}
}
The compiler complains that the local variable total used in println statement at (1) may not be initialized.
Initializing the local variable total before usage solves the problem:
public class SomeClassName{
public static void main(String args[]){
int total = 45; //Local variable initialized with value 45 System.out.println("The incremented total is " + total+ 3); //(1)
}
}
Fields initialization
If no initialization is provided for an instance or static variable, either when declared or in an initializer block, then it is implicitly initialized with the default value of its type.
An instance variable is initialized with the default value of its type each time the class is instantiated, that is for every object created from the class.
A static variable is initialized with the default value of its type when the class is first loaded.
As local variables are allocated on stack, memory chunk for a local variable is allocated when it is assigned with a value.
Take simple example
class Abc {
int i = -111;
int e;
int doSomething() {
int a = 10;
int b = a + i;
int c = b + 100;
Abc d = new Abc();
e = b + c + d.a;
return e + 1000;
}
}
and the bytecode from javap -c Abc
Compiled from "Abc.java"
class Abc {
int i;
int e;
Abc();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush -111
7: putfield #2 // Field i:I
10: return
int doSomething();
Code:
0: bipush 10
2: istore_1
3: iload_1
4: aload_0
5: getfield #2 // Field i:I
8: iadd
9: istore_2
10: iload_2
11: bipush 100
13: iadd
14: istore_3
15: new #3 // class Abc
18: dup
19: invokespecial #4 // Method "<init>":()V
22: astore 4
24: aload_0
25: iload_2
26: iload_3
27: iadd
28: aload 4
30: getfield #2 // Field i:I
33: iadd
34: putfield #5 // Field e:I
37: aload_0
38: getfield #5 // Field e:I
41: sipush 1000
44: iadd
45: ireturn
}
When a method is inovked a memory space in the stack called current frame is allocated
If you look carefully even int a=-111; assignment happens in an implicit init function Abc() !
int a = -111;
5: bipush -111
7: putfield #2 // Field a:I
As field variable e is not assigned any value it will be 0 if primitive or null if a Object reference
And if you look at doSomething()
int a = 10;
0: bipush 10
for a local to be used the initial value needs to be pushed into stack in this case 10 . without this 'push' [initialization] a's value is not accessible to subsequent statements (as the value is not on the stack). once the value is pushed to stack other operations like iadd istore etc are carried out on the stack
below statement actually creates an object on the heap space and invokes init method. This is where un initialized variables like 'e' gets default values
15: new #3 // class Abc
18: dup
I leave further bytecode comparison upto you ;) but I hope it is clear
tl;dr: It was more or less an arbitrary choice
If you ask me, it was a mistake that Java has default values for instance variables. The compiler should have forced the programmer to initialize it before like it is the case for local variables.
The rationale behind the default values is safety. When an object is instantiated, a chunk of memory will be allocated for the object which contains where the instance variables are pointing to etc. The Java designers decided it would be a good idea to wipe this part of memory with zeros and nulls. This way you will never read garbage that happened to be there before the object was allocated. They could have forced initialization; there is nothing fundamental about the choice. It probably made things easy to implement and made enough sense to the designers of Java.
In case of local variables, the designers chose to force initialization (or perhaps it's more accurate to say they chose to not do any kind of initialization when a local variable is only declared, and thus the most logical behavior of the compiler was to force initialization of the variable before use).
The below text is from jls http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
Even then, there are a number of complications. If a final field is
initialized to a compile-time constant expression (§15.28) in the
field declaration, changes to the final field may not be observed,
since uses of that final field are replaced at compile time with the
value of the constant expression.
Can anyone please give me better explanation for the above. I couldn't understand the statement "changes to the final field may not be observed". May with the help of example.
I couldn't understand the statement changes to the final field may not be observed
It tells that , if a final variable is declared as compile time constant then any change made in the final variable using reflection API further in program will not be visible to the program during execution.
For example consider the code given below:
import java.lang.reflect.*;
class ChangeFinal
{
private final int x = 20;//compile time constant
public static void change(ChangeFinal cf)
{
try
{
Class clazz = ChangeFinal.class;
Field field = clazz.getDeclaredField("x");
field.setAccessible(true);
field.set(cf , 190);//changed x to 190 for object cf
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String[] args)
{
ChangeFinal cf = new ChangeFinal();
System.out.println(cf.x);//prints 20
change(cf);
System.out.println(cf.x);//prints 20
}
}
The Output of the above code is:
20
20
WHY?
The answer lies in the output provided by javap -c command for public static void main:
public static void main(java.lang.String[]);
Code:
0: new #3; //class ChangeFinal
3: dup
4: invokespecial #11; //Method "<init>":()V
7: astore_1
8: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Cla
ss;
15: pop
16: bipush 20
18: invokevirtual #14; //Method java/io/PrintStream.println:(I)V
21: aload_1
22: invokestatic #15; //Method change:(LChangeFinal;)V
25: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_1
29: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Cla
ss;
32: pop
33: bipush 20
35: invokevirtual #14; //Method java/io/PrintStream.println:(I)V
38: return
}
At line 16 (before changeFinal method is called)the value of cf.x is hardcoded to 20 . And at line 33 (after changeFinal method is called) the value of cf.x is again hardcoded to 20. Therefore , Although the change in the value of final variable x is done successfully by reflection API during execution, but because of x being a compile time constant it is showing its constant value 20.
It means if in a class you have this:
public class Foo {
public final boolean fooBoolean = true; // true is a constant expression
public final int fooInt = 5; // 5 is a constant expression
}
At compile time any reference to Foo.fooBoolean may be replaced with true, and references to Foo.fooInt may be replaced by 5. If at runtime you later change either of those final fields via reflection, the code referencing it (as it was written) may never see it.
It is quite possible for a Java program to observe a final field having two different values at different times, even without reflection, without recompiling multiple versions of the class, and without anything along those lines. Consider the class below:
class X {
static final int x = getX();
static int getX() {
System.out.println("X.x is now " + X.x);
return 1;
}
public static void main(String[] args) {
System.out.println("X.x is now " + X.x);
}
}
Output:
X.x is now 0
X.x is now 1
This happens because some of the code (the first println) is executed before the field's value is assigned, so that code observes the field's default initial value of 0. The field has a default initial value before it is assigned, even though it is final, because it is not a constant field. The text you quoted from the JLS says this kind of thing cannot happen if the field is declared as a constant.