Are all final variables captured by anonymous classes?
Clash Royale CLAN TAG#URR8PPP
up vote
6
down vote
favorite
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.
java anonymous-class
add a comment |Â
up vote
6
down vote
favorite
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.
java anonymous-class
How do you know thatobj2
is bound tocallback$x
? You have seen it in bytecode?
– Antoniossss
32 mins ago
1
"Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to captureobj2
, but there is no reason it can't.
– Andy Turner
26 mins ago
I think a good reason it would not captureobj2
as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer toobj1
only, whilst another might refer toobj2
only. It wouldn't be sensible for both classes to capture both variables.
– Andy Turner
8 mins ago
add a comment |Â
up vote
6
down vote
favorite
up vote
6
down vote
favorite
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.
java anonymous-class
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.
java anonymous-class
java anonymous-class
asked 41 mins ago
ajb
26.5k33257
26.5k33257
How do you know thatobj2
is bound tocallback$x
? You have seen it in bytecode?
– Antoniossss
32 mins ago
1
"Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to captureobj2
, but there is no reason it can't.
– Andy Turner
26 mins ago
I think a good reason it would not captureobj2
as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer toobj1
only, whilst another might refer toobj2
only. It wouldn't be sensible for both classes to capture both variables.
– Andy Turner
8 mins ago
add a comment |Â
How do you know thatobj2
is bound tocallback$x
? You have seen it in bytecode?
– Antoniossss
32 mins ago
1
"Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to captureobj2
, but there is no reason it can't.
– Andy Turner
26 mins ago
I think a good reason it would not captureobj2
as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer toobj1
only, whilst another might refer toobj2
only. It wouldn't be sensible for both classes to capture both variables.
– Andy Turner
8 mins ago
How do you know that
obj2
is bound to callback$x
? You have seen it in bytecode?– Antoniossss
32 mins ago
How do you know that
obj2
is bound to callback$x
? You have seen it in bytecode?– Antoniossss
32 mins ago
1
1
"Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture
obj2
, but there is no reason it can't.– Andy Turner
26 mins ago
"Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture
obj2
, but there is no reason it can't.– Andy Turner
26 mins ago
I think a good reason it would not capture
obj2
as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer to obj1
only, whilst another might refer to obj2
only. It wouldn't be sensible for both classes to capture both variables.– Andy Turner
8 mins ago
I think a good reason it would not capture
obj2
as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer to obj1
only, whilst another might refer to obj2
only. It wouldn't be sensible for both classes to capture both variables.– Andy Turner
8 mins ago
add a comment |Â
5 Answers
5
active
oldest
votes
up vote
4
down vote
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.
2
Worth mentioning that since Java 8 the restriction on having to explicitly declarefinal
has been lifted. The JLS now talks about "effectivelyfinal
" variables.
– Boris the Spider
28 mins ago
it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
– Carlos Heuberger
2 mins ago
add a comment |Â
up vote
2
down vote
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.
add a comment |Â
up vote
1
down vote
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
andobj1
(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.
add a comment |Â
up vote
-1
down vote
Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
public class Outer
// other code
private Reference<Object> obj1Ref;
private Reference<Object> obj2Ref;
private void method1()
final Object obj1 = new Object();
final Object obj2 = new Object();
obj1Ref = new WeakReference<Object>(obj1);
obj2Ref = new WeakReference<Object>(obj2);
Manager someManager = new Manager();
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.hashCode());
);
// To be called after method1() finishes but before onEvent() get's called.
public void checkReferences ()
Object object1 = obj1Ref.get();
System.out.println("obj1 is still alive: " + object1 != null);
Object object2 = obj1Ref.get();
System.out.println("obj2 is still alive: " + object2 != null);
add a comment |Â
up vote
-2
down vote
This code displays 10, it's unaffected by garbage collector:
public class HelloWorld
public static void main(String args)
Outer q = new Outer();
System.gc();
System.runFinalization();
q.method1().ok(4,1);
interface Ok
public void ok(int a, int b);
class Outer
private final int obj1 = 5;
public Ok method1()
Ok justDoIt = new Ok()
public void ok(int a, int b)
System.out.println(obj1+a+b);
;
return justDoIt;
To be honest I don't exactly understand your question.
But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.
Think of a final variable this way:
public class HelloWorld
public static void main(String args)
Final<Integer> q = new Final();
q.set(5);
System.out.println(q.get());
q.set(10); // ERROR
class Final <T>
private T variable;
private Boolean setted=false;
public void set(T value) throws Error
if(setted)
throw new Error();
variable=value;
setted = true;
public T get()return variable;
And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it
If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
– Rab
9 mins ago
OP meant that he thought that evenobj2
is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
– Antoniossss
9 mins ago
I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
– Nertan Lucian
6 mins ago
You are missing the point and if you answered base on title, it is still off topic IMHO.
– Antoniossss
5 mins ago
add a comment |Â
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
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.
2
Worth mentioning that since Java 8 the restriction on having to explicitly declarefinal
has been lifted. The JLS now talks about "effectivelyfinal
" variables.
– Boris the Spider
28 mins ago
it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
– Carlos Heuberger
2 mins ago
add a comment |Â
up vote
4
down vote
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.
2
Worth mentioning that since Java 8 the restriction on having to explicitly declarefinal
has been lifted. The JLS now talks about "effectivelyfinal
" variables.
– Boris the Spider
28 mins ago
it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
– Carlos Heuberger
2 mins ago
add a comment |Â
up vote
4
down vote
up vote
4
down vote
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.
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.
edited 25 mins ago
answered 32 mins ago


Andreas
72.3k454115
72.3k454115
2
Worth mentioning that since Java 8 the restriction on having to explicitly declarefinal
has been lifted. The JLS now talks about "effectivelyfinal
" variables.
– Boris the Spider
28 mins ago
it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
– Carlos Heuberger
2 mins ago
add a comment |Â
2
Worth mentioning that since Java 8 the restriction on having to explicitly declarefinal
has been lifted. The JLS now talks about "effectivelyfinal
" variables.
– Boris the Spider
28 mins ago
it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
– Carlos Heuberger
2 mins ago
2
2
Worth mentioning that since Java 8 the restriction on having to explicitly declare
final
has been lifted. The JLS now talks about "effectively final
" variables.– Boris the Spider
28 mins ago
Worth mentioning that since Java 8 the restriction on having to explicitly declare
final
has been lifted. The JLS now talks about "effectively final
" variables.– Boris the Spider
28 mins ago
it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
– Carlos Heuberger
2 mins ago
it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
– Carlos Heuberger
2 mins ago
add a comment |Â
up vote
2
down vote
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.
add a comment |Â
up vote
2
down vote
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.
add a comment |Â
up vote
2
down vote
up vote
2
down vote
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.
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.
answered 13 mins ago
Andy Turner
77.3k876124
77.3k876124
add a comment |Â
add a comment |Â
up vote
1
down vote
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
andobj1
(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.
add a comment |Â
up vote
1
down vote
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
andobj1
(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.
add a comment |Â
up vote
1
down vote
up vote
1
down vote
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
andobj1
(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.
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
andobj1
(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.
answered 14 mins ago
Antoniossss
14.5k12149
14.5k12149
add a comment |Â
add a comment |Â
up vote
-1
down vote
Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
public class Outer
// other code
private Reference<Object> obj1Ref;
private Reference<Object> obj2Ref;
private void method1()
final Object obj1 = new Object();
final Object obj2 = new Object();
obj1Ref = new WeakReference<Object>(obj1);
obj2Ref = new WeakReference<Object>(obj2);
Manager someManager = new Manager();
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.hashCode());
);
// To be called after method1() finishes but before onEvent() get's called.
public void checkReferences ()
Object object1 = obj1Ref.get();
System.out.println("obj1 is still alive: " + object1 != null);
Object object2 = obj1Ref.get();
System.out.println("obj2 is still alive: " + object2 != null);
add a comment |Â
up vote
-1
down vote
Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
public class Outer
// other code
private Reference<Object> obj1Ref;
private Reference<Object> obj2Ref;
private void method1()
final Object obj1 = new Object();
final Object obj2 = new Object();
obj1Ref = new WeakReference<Object>(obj1);
obj2Ref = new WeakReference<Object>(obj2);
Manager someManager = new Manager();
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.hashCode());
);
// To be called after method1() finishes but before onEvent() get's called.
public void checkReferences ()
Object object1 = obj1Ref.get();
System.out.println("obj1 is still alive: " + object1 != null);
Object object2 = obj1Ref.get();
System.out.println("obj2 is still alive: " + object2 != null);
add a comment |Â
up vote
-1
down vote
up vote
-1
down vote
Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
public class Outer
// other code
private Reference<Object> obj1Ref;
private Reference<Object> obj2Ref;
private void method1()
final Object obj1 = new Object();
final Object obj2 = new Object();
obj1Ref = new WeakReference<Object>(obj1);
obj2Ref = new WeakReference<Object>(obj2);
Manager someManager = new Manager();
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.hashCode());
);
// To be called after method1() finishes but before onEvent() get's called.
public void checkReferences ()
Object object1 = obj1Ref.get();
System.out.println("obj1 is still alive: " + object1 != null);
Object object2 = obj1Ref.get();
System.out.println("obj2 is still alive: " + object2 != null);
Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
public class Outer
// other code
private Reference<Object> obj1Ref;
private Reference<Object> obj2Ref;
private void method1()
final Object obj1 = new Object();
final Object obj2 = new Object();
obj1Ref = new WeakReference<Object>(obj1);
obj2Ref = new WeakReference<Object>(obj2);
Manager someManager = new Manager();
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.hashCode());
);
// To be called after method1() finishes but before onEvent() get's called.
public void checkReferences ()
Object object1 = obj1Ref.get();
System.out.println("obj1 is still alive: " + object1 != null);
Object object2 = obj1Ref.get();
System.out.println("obj2 is still alive: " + object2 != null);
answered 13 mins ago
aka-one
1,05118
1,05118
add a comment |Â
add a comment |Â
up vote
-2
down vote
This code displays 10, it's unaffected by garbage collector:
public class HelloWorld
public static void main(String args)
Outer q = new Outer();
System.gc();
System.runFinalization();
q.method1().ok(4,1);
interface Ok
public void ok(int a, int b);
class Outer
private final int obj1 = 5;
public Ok method1()
Ok justDoIt = new Ok()
public void ok(int a, int b)
System.out.println(obj1+a+b);
;
return justDoIt;
To be honest I don't exactly understand your question.
But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.
Think of a final variable this way:
public class HelloWorld
public static void main(String args)
Final<Integer> q = new Final();
q.set(5);
System.out.println(q.get());
q.set(10); // ERROR
class Final <T>
private T variable;
private Boolean setted=false;
public void set(T value) throws Error
if(setted)
throw new Error();
variable=value;
setted = true;
public T get()return variable;
And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it
If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
– Rab
9 mins ago
OP meant that he thought that evenobj2
is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
– Antoniossss
9 mins ago
I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
– Nertan Lucian
6 mins ago
You are missing the point and if you answered base on title, it is still off topic IMHO.
– Antoniossss
5 mins ago
add a comment |Â
up vote
-2
down vote
This code displays 10, it's unaffected by garbage collector:
public class HelloWorld
public static void main(String args)
Outer q = new Outer();
System.gc();
System.runFinalization();
q.method1().ok(4,1);
interface Ok
public void ok(int a, int b);
class Outer
private final int obj1 = 5;
public Ok method1()
Ok justDoIt = new Ok()
public void ok(int a, int b)
System.out.println(obj1+a+b);
;
return justDoIt;
To be honest I don't exactly understand your question.
But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.
Think of a final variable this way:
public class HelloWorld
public static void main(String args)
Final<Integer> q = new Final();
q.set(5);
System.out.println(q.get());
q.set(10); // ERROR
class Final <T>
private T variable;
private Boolean setted=false;
public void set(T value) throws Error
if(setted)
throw new Error();
variable=value;
setted = true;
public T get()return variable;
And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it
If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
– Rab
9 mins ago
OP meant that he thought that evenobj2
is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
– Antoniossss
9 mins ago
I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
– Nertan Lucian
6 mins ago
You are missing the point and if you answered base on title, it is still off topic IMHO.
– Antoniossss
5 mins ago
add a comment |Â
up vote
-2
down vote
up vote
-2
down vote
This code displays 10, it's unaffected by garbage collector:
public class HelloWorld
public static void main(String args)
Outer q = new Outer();
System.gc();
System.runFinalization();
q.method1().ok(4,1);
interface Ok
public void ok(int a, int b);
class Outer
private final int obj1 = 5;
public Ok method1()
Ok justDoIt = new Ok()
public void ok(int a, int b)
System.out.println(obj1+a+b);
;
return justDoIt;
To be honest I don't exactly understand your question.
But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.
Think of a final variable this way:
public class HelloWorld
public static void main(String args)
Final<Integer> q = new Final();
q.set(5);
System.out.println(q.get());
q.set(10); // ERROR
class Final <T>
private T variable;
private Boolean setted=false;
public void set(T value) throws Error
if(setted)
throw new Error();
variable=value;
setted = true;
public T get()return variable;
And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it
This code displays 10, it's unaffected by garbage collector:
public class HelloWorld
public static void main(String args)
Outer q = new Outer();
System.gc();
System.runFinalization();
q.method1().ok(4,1);
interface Ok
public void ok(int a, int b);
class Outer
private final int obj1 = 5;
public Ok method1()
Ok justDoIt = new Ok()
public void ok(int a, int b)
System.out.println(obj1+a+b);
;
return justDoIt;
To be honest I don't exactly understand your question.
But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.
Think of a final variable this way:
public class HelloWorld
public static void main(String args)
Final<Integer> q = new Final();
q.set(5);
System.out.println(q.get());
q.set(10); // ERROR
class Final <T>
private T variable;
private Boolean setted=false;
public void set(T value) throws Error
if(setted)
throw new Error();
variable=value;
setted = true;
public T get()return variable;
And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it
answered 10 mins ago


Nertan Lucian
9219
9219
If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
– Rab
9 mins ago
OP meant that he thought that evenobj2
is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
– Antoniossss
9 mins ago
I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
– Nertan Lucian
6 mins ago
You are missing the point and if you answered base on title, it is still off topic IMHO.
– Antoniossss
5 mins ago
add a comment |Â
If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
– Rab
9 mins ago
OP meant that he thought that evenobj2
is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
– Antoniossss
9 mins ago
I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
– Nertan Lucian
6 mins ago
You are missing the point and if you answered base on title, it is still off topic IMHO.
– Antoniossss
5 mins ago
If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
– Rab
9 mins ago
If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
– Rab
9 mins ago
OP meant that he thought that even
obj2
is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.– Antoniossss
9 mins ago
OP meant that he thought that even
obj2
is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.– Antoniossss
9 mins ago
I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
– Nertan Lucian
6 mins ago
I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
– Nertan Lucian
6 mins ago
You are missing the point and if you answered base on title, it is still off topic IMHO.
– Antoniossss
5 mins ago
You are missing the point and if you answered base on title, it is still off topic IMHO.
– Antoniossss
5 mins ago
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53203529%2fare-all-final-variables-captured-by-anonymous-classes%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
How do you know that
obj2
is bound tocallback$x
? You have seen it in bytecode?– Antoniossss
32 mins ago
1
"Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture
obj2
, but there is no reason it can't.– Andy Turner
26 mins ago
I think a good reason it would not capture
obj2
as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer toobj1
only, whilst another might refer toobj2
only. It wouldn't be sensible for both classes to capture both variables.– Andy Turner
8 mins ago