Note: edited on 16/5/2013 to add info about enum constructors as well.

About Java inner classes

Java allows member classes (classes that are defined inside other classes), local classes
(classes that are defined inside statement blocks) and anonymous classes (classes with no
names):

class Outer {
Object anonymous = new Object(){}; // this is an anonymous class
// anonymous initialisation block
{
// this is a local class
class Local{}
Local l = new Local();
}
Outer() {
// this is a local named class in a constructor
class Local{}
Local l = new Local();
}
void method() {
// this is a local named class in a method
class Local{}
Local l = new Local();
}
// this is a member class
class Inner{}
Inner i = new Inner();
}

Implementation “details”

What the Java Language or Virtual Machine specifications do not tell you is how they are implemented.
Some of it is explained already in other articles,
such as how the Java compiler generates synthetic methods to allow these members classes access to
private fields, which would not be allowed by the JVM.

Another implementation detail of inner classes that is handy to know is that inner class constructors
take extra synthetic parameters. It is relatively
well-known
that the first synthetic parameter of an inner class constructor will be its enclosing instance, which
it will store in a this$X synthetic field. This is valid for all three kinds of inner classes: member,
local and anonymous.

But it is generally not known that local classes who capture non-constant final variables will require
all these variables to be passed as extra synthetic constructor parameters (captured constant final
variables will be inlined and not generate extra synthetic constructor parameters):

Luckily, enums can’t be inner classes, so they will not have an extra synthetic parameter inserted for
the container instance to add to those two.

OK, but why should I care?

In most cases you don’t care, other than for your own curiosity. But if you’re doing Java reflection with inner or enum classes,
there are a few things you should know, and because I haven’t found them listed or specified online, I thought it would
be important to make a list of things to help others figure it out, because different compilers will produce different
results in the Java reflection API.

The question is what happens when you use Java reflection to get a java.lang.reflect.Constructor instance for inner or enum
class constructors? In particular, what happens with the methods that allow you to access the parameter types (pre-generics:
getParameterTypes()), the generic parameter types (post-generics: getGenericParameterTypes()) and annotations
(getParameterAnnotations()), and the answer is: it depends.

Here are the size of the arrays returned by these three reflection methods, on each of our
constructor, and how they differ depending on the Java compiler used:

Outer.Inner.class .getDeclaredConstructor()

Outer.Inner.class .getDeclaredConstructor( String.class)

Outer.Inner.class .getDeclaredConstructor( Integer.class)

getParameterTypes() .length

1

2

2

getGenericParameterTypes() .length compiled with Eclipse

1

2

2

getGenericParameterTypes() .length compiled with Javac

0

1

1

getParameterAnnotations() .length

1

2

1

And the results are consistent for our enum class:

Enum.class .getDeclaredConstructor()

Enum.class .getDeclaredConstructor( String.class)

Enum.class .getDeclaredConstructor( Integer.class)

getParameterTypes() .length

2

3

3

getGenericParameterTypes() .length compiled with Eclipse

2

3

3

getGenericParameterTypes() .length compiled with Javac

0

1

1

getParameterAnnotations() .length

2

3

1

As you can see, the synthetic parameters are always included in getParameterTypes(),
but are only included in getGenericParameterTypes() when compiled with Eclipse.

getParameterAnnotations() on the other hand, will always include synthetic parameters
except when at least one of your constructor parameters are annotated.

With this info, you now understand the differences between the results of these methods,
but so far I still haven’t found a way to determine which parameter is synthetic or not,
because although you can make a good guess for the this$X synthetic parameter, which
is required by every inner class, you have no way of knowing the number of non-constant
captured variables that will end up as synthetic parameters to local class constructors.