I am trying to check for default value of instance variables (i.e. 0 here) in the generated bytecode.
I can see <init>() getting called and if I print myvar instance variable inside constructor then I see getfield called for myvar but then where was this default set first?
Please answer on following:
When is default value being set in myvar? (after compilation or object creation time)
Who(compiler or jvm) is initializing(or let's say setting default value) in the instance variable?
public class FieldInit {
int myvar;
public static void main(String[] args) {
new FieldInit(); // and what would happen if I comment out this
}
}
I am trying to deassemble bytecode using javap but not able to see the <clinit>() method, I guess here this may be happening. Please let me know if it is possible to see <clinit>() method and if so, how?
In JVM, an object instantiation is split into two bytecode instructions:
new allocates a new uninitialized object;
invokespecial calls a constructor that initializes the object.
The JVM Specification for the new bytecode says:
Memory for a new instance of that class is allocated from the
garbage-collected heap, and the instance variables of the new object
are initialized to their default initial values
The JVM sets all instance fields to zeroes when executing new instruction. So, by the time a constructor is invoked, all fields are already set to their default values. You will not find this "zeroing" in the bytecode - it's done implicitly by the JVM during object allocation.
Your question is not answerable because it's more complicated than you think it is.
fields in java are encoded in a field datastructure and this datastructure includes room for the initial value. However, the only possible initial values in this data structure are numbers and strings.
Let's see it in action! (and note that L is just a java syntax thing to tell java: This number is a long, not an int. 5 is a constant, so is 5L).
class Test {
public static final long mark = 5L;
}
javac Test.java
javap -v c Test
.....
public static final long mark;
descriptor: J
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: long 5l
Hey look there it is, constant value 5L.
But what if it isn't constant?
Ah, that's a problem. You can't encode that here.
So, instead, it's syntax sugar time!
You can write a special method in any class that is run during a class's static initialization. You can also write a special method that is run as a new instance is made. That one is almost entirely the same as a constructor, with only exotic differences. It looks like this:
public class Test {
static {
System.out.println("What voodoo magic is this?");
}
public static void main(String[] args) {
System.out.println("In main");
}
}
Let's see it in action!
javac Test.java
java Test
What voodoo magic is this?
In main
javap -c -v Test
...
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: getstatic #7 // Field >java/lang/System.out:Ljava/io/PrintStream;
3: ldc #21 // String Voodoo...
5: invokevirtual #15 // Method >java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 3: 0
line 4: 8
}
As you can see, that weird static{} thing was compiled to something that looks exactly like a method, bytecode and all, but the name of the method is bizarre, it's just static{}.
Here comes the clue
But what happens if we make that a little more complicated. Let's initialize this field to the current time, instead!
class Test {
public static final long mark = System.currentTimeMillis();
}
This is just syntax sugar. That explains how this works, because as I told you, at the class file level, you cannot initialize fields with non-constants. Thus, that compiles to the same thing as:
class Test {
public static final long mark;
static {
mark = System.currentTimeMillis();
}
}
and you can javap to confirm this.
One is called a 'compile time constant'. The other isn't. This shows up in various ways. For example, you can pass a CTC as annotation parameter. Try that: try using static final long MARK = 5L; (you will be able to), then static final long MARK = System.currentTimeMillis(); - that won't be allowed.
So, where is that initial value? If it's a constant value, javap -c -v will show it. If it isn't, it's stuck in the static block.
Related
I thought I knew the answer to this, but I can't find any confirmation after an hour or so of searching.
In this code:
public class Outer {
// other code
private void method1() {
final SomeObject obj1 = new SomeObject(...);
final SomeObject obj2 = new SomeObject(...);
someManager.registerCallback(new SomeCallbackClass() {
#Override
public void onEvent() {
System.out.println(obj1.getName());
}
});
}
}
Assume that registerCallback saves its parameter somewhere, so that the object of the anonymous subclass will live for a while. Obviously this object has to maintain a reference to obj1 so that onEvent will work if it is called.
But given that the object doesn't use obj2, does it still maintain a reference to obj2, so that obj2 can't be garbage-collected while the object lives? I was under the impression that all visible final (or effectively final) local variables and parameters were captured and thus couldn't be GC'ed as long as the object was alive, but I can't find anything that says one way or the other.
Is it implementation-dependent?
Is there a section in the JLS that answers this? I wasn't able to find the answer there.
The language spec has very little to say about how anonymous classes should capture variables from their enclosing scope.
The only especially relevant section of the language spec that I can find is JLS Sec 8.1.3:
Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.)
(Anonymous classes are inner classes)
It does not specify anything about which variables the anonymous class should capture, or how that capturing should be implemented.
I think it is reasonable to infer from this that implementations need not capture variables that aren't referenced in the inner class; but it doesn't say they can't.
Only obj1 is captured.
Logically, the anonymous class is implemented as a normal class something like this:
class Anonymous1 extends SomeCallbackClass {
private final Outer _outer;
private final SomeObject obj1;
Anonymous1(Outer _outer, SomeObject obj1) {
this._outer = _outer;
this.obj1 = obj1;
}
#Override
public void onEvent() {
System.out.println(this.obj1.getName());
}
});
Note that an anonymous class is always an inner class, so it will always maintain a reference to the outer class, even if it doesn't need it. I don't know if later versions of the compiler have optimized that away, but I don't think so. It is a potential cause of memory leaks.
The use of it becomes:
someManager.registerCallback(new Anonymous1(this, obj1));
As you can see, the reference value of obj1 is copied (pass-by-value).
There is technically no reason for obj1 to be final, whether declared final or effectively final (Java 8+), except that if it wasn't and you change the value, the copy wouldn't change, causing bugs because you expected the value to change, given that the copying is a hidden action. To prevent programmer confusion, they decided that obj1 must be final, so you can never become confused about that behavior.
I was curious and surprised by your statement that much (why would compiler do such thing???), that I had to check it myself. So I made simple example like this
public class test {
private static Object holder;
private void method1() {
final Object obj1 = new Object();
final Object obj2 = new Object();
holder = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(obj1);
}
};
}
}
And resulted with following bytecode for of method1
private method1()V
L0
LINENUMBER 8 L0
NEW java/lang/Object
DUP
INVOKESPECIAL java/lang/Object.<init> ()V
ASTORE 1
L1
LINENUMBER 9 L1
NEW java/lang/Object
DUP
INVOKESPECIAL java/lang/Object.<init> ()V
ASTORE 2
L2
LINENUMBER 10 L2
NEW test$1
DUP
ALOAD 0
ALOAD 1
INVOKESPECIAL test$1.<init> (Ltest;Ljava/lang/Object;)V
PUTSTATIC test.holder : Ljava/lang/Object;
Which means:
L0 - store first final with idx 1 (ASTORE 1)
L1 - store second final with idx 2(that one is not used in anon class) (ASTORE 2)
L2 - create new test$1 with argumets (ALOAD 0) this and obj1 (ALOAD 1)
So I have no idea, how did you get to the conclusion that obj2 is passed to anonymous class instance, but it was simply wrong. IDK if it is compiler dependent, but as for what other has stated, it is not impossible.
obj2 will be garbage collected since it has no reference to it. obj1 will not be garbage collected as long as the event is active since even if you created an anonymous class, you've created a direct reference to obj1.
The only thing final does is that you can't re-define the value, it doesn't protect the object from the garbage collector
In java, say I have the following
==fileA.java==
class A
{
public static final int SIZE = 100;
}
Then in another file I use this value
==fileB.java==
import A;
class b
{
Object[] temp = new Object[A.SIZE];
}
When this gets compiled does SIZE get replaced with the value 100, so that if I were to replace the FileA.jar but not FileB.jar, would the object array get the new value or would it have been hardcoded to 100 because that's the value when it was originally built?
Yes, the Java compiler does replace static constant values like SIZE in your example with their literal values.
So, if you would later change SIZE in class A but you don't recompile class b, you will still see the old value in class b. You can easily test this out:
file A.java
public class A {
public static final int VALUE = 200;
}
file B.java
public class B {
public static void main(String[] args) {
System.out.println(A.VALUE);
}
}
Compile A.java and B.java. Now run: java B
Change the value in A.java. Recompile A.java, but not B.java. Run again, and you'll see the old value being printed.
You can keep the constant from being compiled into B, by doing
class A
{
public static final int SIZE;
static
{
SIZE = 100;
}
}
Another route to proving that the behavior is to looking at the generated bytecode. When the constant is "small" (presumably < 128):
public B();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 42
7: anewarray #3; //class java/lang/Object
10: putfield #12; //Field temp:[Ljava/lang/Object;
13: return
}
(I used 42 instead of 100 so it stands out more). In this case, it is clearly substituted in the byte code. But, say the constant is "bigger." Then you get byte code that looks like this:
public B();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #12; //int 86753098
7: anewarray #3; //class java/lang/Object
10: putfield #13; //Field temp:[Ljava/lang/Object;
13: return
When it is bigger, the opcode "ldc" is used, which according to the JVM documentation "an unsigned byte that must be a valid index into the runtime constant pool of the current class".
In either case, the constant is embedded into B. I imagine, since that in opcodes you can only access the current classes runtime constant pool, that this the decision to write the constant into the class file is independent of implementation (but I don't know that for a fact).
Woo - you learn something new everyday!
Taken from the Java spec...
Note: If a primitive type or a string
is defined as a constant and the value
is known at compile time, the compiler
replaces the constant name everywhere
in the code with its value. This is
called a compile-time constant. If the
value of the constant in the outside
world changes (for example, if it is
legislated that pi actually should be
3.975), you will need to recompile any classes that use this constant to get
the current value.
The important concept here is that the static final field is initialised with a compile-time constant, as defined in the JLS. Use a non-constant initialiser (or non-static or non-final) and it wont be copied:
public static final int SIZE = null!=null?0: 100;
(null is not a *compile-time constant`.)
Actually I ran into this bizarreness a while ago.
This will compile "100" into class b directly. If you just recompile class A, this will not update the value in class B.
On top of that, the compiler may not notice to recompile class b (at the time I was compiling single directories and class B was in a separate directory and compiling a's directory did not trigger a compile of B)
As an optimization the compiler will inline that final variable.
So at compile time it will look like.
class b
{
Object[] temp = new Object[100];
}
One thing should note is: static final value is known at compile time
if the value is not known at compile time, compiler won't replaces the constant name everywhere in the code with its value.
public class TestA {
// public static final int value = 200;
public static final int value = getValue();
public static int getValue() {
return 100;
}
}
public class TestB {
public static void main(String[] args) {
System.out.println(TestA.value);
}
}
first compile TestA and TestB, run TestB
then change TestA.getValue() to return 200, compile TestA, run TestB, TestB will get the new value
enter image description here
There is an exception to this:-
If static final field is null at the time of compiling then it doesn't get replaced with null (which is actually its value)
A.java
class A{
public static final String constantString = null;
}
B.java
class B{
public static void main(String... aa){
System.out.println(A.constantString);
}
}
Compile both A.java and B.java and run java B
Output will be null
Now Update A.java with following code and compile only this class.
class A{
public static final String constantString = "Omg! picking updated value without re-compilation";
}
Now run java B
Output will be Omg! picking updated value without re-compilation
Java does optimise these sorts of values but only if they are in the same class. In this case the JVM looks in A.SIZE rather than optimizing it because of the usage case you are considering.
I thought I knew the answer to this, but I can't find any confirmation after an hour or so of searching.
In this code:
public class Outer {
// other code
private void method1() {
final SomeObject obj1 = new SomeObject(...);
final SomeObject obj2 = new SomeObject(...);
someManager.registerCallback(new SomeCallbackClass() {
#Override
public void onEvent() {
System.out.println(obj1.getName());
}
});
}
}
Assume that registerCallback saves its parameter somewhere, so that the object of the anonymous subclass will live for a while. Obviously this object has to maintain a reference to obj1 so that onEvent will work if it is called.
But given that the object doesn't use obj2, does it still maintain a reference to obj2, so that obj2 can't be garbage-collected while the object lives? I was under the impression that all visible final (or effectively final) local variables and parameters were captured and thus couldn't be GC'ed as long as the object was alive, but I can't find anything that says one way or the other.
Is it implementation-dependent?
Is there a section in the JLS that answers this? I wasn't able to find the answer there.
The language spec has very little to say about how anonymous classes should capture variables from their enclosing scope.
The only especially relevant section of the language spec that I can find is JLS Sec 8.1.3:
Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.)
(Anonymous classes are inner classes)
It does not specify anything about which variables the anonymous class should capture, or how that capturing should be implemented.
I think it is reasonable to infer from this that implementations need not capture variables that aren't referenced in the inner class; but it doesn't say they can't.
Only obj1 is captured.
Logically, the anonymous class is implemented as a normal class something like this:
class Anonymous1 extends SomeCallbackClass {
private final Outer _outer;
private final SomeObject obj1;
Anonymous1(Outer _outer, SomeObject obj1) {
this._outer = _outer;
this.obj1 = obj1;
}
#Override
public void onEvent() {
System.out.println(this.obj1.getName());
}
});
Note that an anonymous class is always an inner class, so it will always maintain a reference to the outer class, even if it doesn't need it. I don't know if later versions of the compiler have optimized that away, but I don't think so. It is a potential cause of memory leaks.
The use of it becomes:
someManager.registerCallback(new Anonymous1(this, obj1));
As you can see, the reference value of obj1 is copied (pass-by-value).
There is technically no reason for obj1 to be final, whether declared final or effectively final (Java 8+), except that if it wasn't and you change the value, the copy wouldn't change, causing bugs because you expected the value to change, given that the copying is a hidden action. To prevent programmer confusion, they decided that obj1 must be final, so you can never become confused about that behavior.
I was curious and surprised by your statement that much (why would compiler do such thing???), that I had to check it myself. So I made simple example like this
public class test {
private static Object holder;
private void method1() {
final Object obj1 = new Object();
final Object obj2 = new Object();
holder = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(obj1);
}
};
}
}
And resulted with following bytecode for of method1
private method1()V
L0
LINENUMBER 8 L0
NEW java/lang/Object
DUP
INVOKESPECIAL java/lang/Object.<init> ()V
ASTORE 1
L1
LINENUMBER 9 L1
NEW java/lang/Object
DUP
INVOKESPECIAL java/lang/Object.<init> ()V
ASTORE 2
L2
LINENUMBER 10 L2
NEW test$1
DUP
ALOAD 0
ALOAD 1
INVOKESPECIAL test$1.<init> (Ltest;Ljava/lang/Object;)V
PUTSTATIC test.holder : Ljava/lang/Object;
Which means:
L0 - store first final with idx 1 (ASTORE 1)
L1 - store second final with idx 2(that one is not used in anon class) (ASTORE 2)
L2 - create new test$1 with argumets (ALOAD 0) this and obj1 (ALOAD 1)
So I have no idea, how did you get to the conclusion that obj2 is passed to anonymous class instance, but it was simply wrong. IDK if it is compiler dependent, but as for what other has stated, it is not impossible.
obj2 will be garbage collected since it has no reference to it. obj1 will not be garbage collected as long as the event is active since even if you created an anonymous class, you've created a direct reference to obj1.
The only thing final does is that you can't re-define the value, it doesn't protect the object from the garbage collector
Given the following enum:
enum Repeat {
Daily,
Weekly,
Yearly
}
I realize we are able to write it this way:
Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;
which is equivalent to:
Repeat repeat = Repeat.Weekly;
May I know why such syntax is allowed? Is there a way to let the compiler warn us against this?
This is allowed as Daily, Weekly, Yearly are the static field by default inside the enum and holds the object of Repeat. Also, you will get a warning from the compiler "The static field Repeat.Weekly should be accessed in a static way". It is similar to below lines of code.
class Foo{
public static Foo obj1 = new Foo();
public static Foo obj2 = new Foo();
public static Foo obj3 = new Foo();
}
Foo f = Foo.obj1.obj2.obj3; // will work fine but you will get a warning from the compiler.
Here is some part of bytecode inspection of Repeat enum and from this, it is clear that Enum variable is static and holds the Object of Enum itself.
0: new #1 // class com/java8/demo/Repeat
3: dup
4: ldc #14 // String Daily
6: iconst_0
7: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #19 // Field Daily:Lcom/java8/demo/Repeat;
13: new #1 // class com/java8/demo/Repeat
Enum instance are just static instance of the enum class.
We have two way to access static field of a class:
Via class itselft: Repeat.Daily
Via instance of class: Repeat.Daily.Daily
When you chain your enum:
Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;
It's just like get a static field from an instance of a class.
Is there a way to let compiler warn us against this?
Yes, use a good IDE and turn on warning. That way, you'll be notified as soon as your write the code, before you even compile it.
E.g. in Eclipse, it is called "Non-static access to static member":
Enum literals are static members, and with each static member, one can access them either using the class reference:
TypeName.staticMember
TypeName.staticMethod()
Or on an instance:
new TypeName().staticMember
new TypeName().staticMethod()
The second approach is discouraged (and the compiler will issue a warning)
As enum literals are just static members, Repeat.Daily.Weekly.Yearly.Weekly is like the second code snippet above, accessing static members on instance references.
With a class, that would be:
class Type {
static Type INSTANCE1, INSTANCE2, INSTANCE3;
}
And one can get a reference to INSTANCE3 using Type.INSTANCE1.INSTANCE2.INSTANCE3. It's valid, but it's bad practice.
How do static methods actually run in Java? We usually invoke them using the class name, and do not create any object for them, but these are objects which actually can "run", not methods!
For static methods, a special keyword is available and added as part of the byte-code. It is called invokestatic.
From Oracle docs :
invokestatic
Operation
Invoke a class (static) method
Description :
The unsigned indexbyte1 and indexbyte2 are used to construct an index
into the run-time constant pool of the current class (§2.6), where the
value of the index is (indexbyte1 << 8) | indexbyte2. The run-time
constant pool item at that index must be a symbolic reference to a
method (§5.1), which gives the name and descriptor (§4.3.3) of the
method as well as a symbolic reference to the class in which the
method is to be found. The named method is resolved (§5.4.3.3). The
resolved method must not be an instance initialization method (§2.9)
or the class or interface initialization method (§2.9). It must be
static, and therefore cannot be abstract.
On successful resolution of the method, the class that declared the
resolved method is initialized (§5.5) if that class has not already
been initialized.
The operand stack must contain nargs argument values, where the
number, type, and order of the values must be consistent with the
descriptor of the resolved method.
Sample code :
public class Example {
static void myStaticMethod() {
System.out.println("Hello");
}
public static void main(String[] args) {
myStaticMethod();
}
}
Byte code :
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=1, args_size=1
0: invokestatic #31 // Method myStaticMethod:()V
3: return
LineNumberTable:
line 8: 0
line 9: 3
LocalVariableTable:
Start Length Slot Name Signature
0 4 0 args [Ljava/lang/String;
Runtime constant pool of class :
...
#31 = Methodref #1.#32 // Example.myStaticMethod:()V
...
In case of static method Java loads the method when the class is loaded and shares the method with all the objects also and that's why an object is not necessary.
It's not always necessary to have an object in order to run a method.
And no, it's not the object that runs. It's the method that does the operation and objects or classes hold them as a property.