In Java programs, every instance of an inner class has an
immediately enclosing instance. When an inner class is instantiated
with the new
keyword, the immediately enclosing
instance is passed to the inner class's constructor via a parameter
not visible in source code. The Java Language Specification
(§15.9.4) requires that the immediately enclosing instance is not
null.
Prior to JDK 25, javac
inserted a null check on the
immediately enclosing instance before it was passed to the inner
class's constructor. No null check was performed in the body of the
inner class's constructor. As a result, it was possible to use core
reflection, e.g.,
java.lang.reflect.Constructor::newInstance
, or
specially crafted class
files to invoke an inner
class's constructor with null as the immediately enclosing
instance. This could lead to unexpected program failures.
In JDK 25, javac
inserts an additional null check
on the immediately enclosing instance. This check occurs in the
body of the inner class's constructor. As a result, there is no way
to instantiate an inner class with null as the immediately
enclosing instance.
In the extremely rare case of needing to run legacy code that
passes null as the immediately enclosing instance, developers can,
at their own risk, use the unsupported option
-XDnullCheckOuterThis=false
. This prevents
javac
from inserting the additional null check in
inner class constructor bodies.