As of JDK 18, no. JDK 18 omits enclosing instance fields from inner classes that don’t use it.
However, prior to JDK 18, yes, instances of anonymous inner classes hold on to a reference to their enclosing instances even if these references are never actually used. For example, this code:
public class Outer {
public Runnable getRunnable() {
return new Runnable() {
public void run() {
System.out.println("hello");
}
};
}
}
…when compiled with javac
, generates two class files: Outer.class
and
Outer$1.class
. Disassembling the latter, the anonymous inner class,
with javap -c
yields:
Compiled from "Outer.java"
class Outer$1 extends java.lang.Object implements java.lang.Runnable{
final Outer this$0;
Outer$1(Outer);
Code:
0: aload_0
1: aload_1
2: putfield #1; //Field this$0:LOuter;
5: aload_0
6: invokespecial #2; //Method java/lang/Object."<init>":()V
9: return
public void run();
Code:
0: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4; //String hello
5: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
The putfield
line shows that a reference to the enclosing instance is
being stored in the field this$0
(of type Outer
) by the constructor
even though this field is never used again.
This is unfortunate if you’re attempting to create small potentially
long-lived objects with anonymous inner classes as they’ll hold onto the
(potentially large) enclosing instance. A workaround is to use an instance of a static class (or a top-level class) instead. This is unfortunately more verbose.