Last week, I was working with different type of nested classes and found an interesting fact (which I overlooked up-till now) regarding no-arguments default constructor in some of the nested classes.
Before, I illustrate the example, as a refresher, lets briefly look how many types of Nested Classes are supported in Java.
Types of Nested Classes supported in Java:
- Static Nested Class – a static class nested inside another class
- Non-Static Nested Class – also called Inner Class – a non static class nested inside another class. Besides that, there are two other, special kinds of Inner Classes:
- Local Class – a named Inner Class
- Anonymous Class – an un-named Inner Class
Consider following class, in which I tried to create all different sorts of test cases regarding nested classes. Although I don’t wanted to add any extra code to illustrate these cases, but in order to gain “access” to certain members, I had to open doors here and there, please ignore them.
/** | |
* No-Arguments Default Constructor and Nested Classes (Non-Static Inner Class, Local Class, Anonymous Class) | |
* http://codeoftheday.blogspot.com/2013/07/no-arguments-default-constructor-and.html | |
*/ | |
package com.smhumayun.codeoftheday.NestedClassesExample; | |
interface AnInterface {} | |
public class TopLevelClass { | |
static class StaticClassInsideTopLevelClass {} | |
class NonStaticClassInsideTopLevelClass {} | |
AnInterface anonymousClassObj1 = new AnInterface() {}; | |
static { | |
class ClassInsideStaticBlock {} | |
AnInterface anonymousClassObj2 = new AnInterface() {}; //anonymous class | |
/*Ignore*/ classInsideStaticBlock = ClassInsideStaticBlock.class; | |
/*Ignore*/ anonymousClassInsideStaticBlock = anonymousClassObj2.getClass(); | |
} | |
static void staticMethod () { | |
class ClassInsideStaticMethod {} | |
AnInterface anonymousClassObj3 = new AnInterface() {}; //anonymous class | |
/*Ignore*/ classInsideStaticMethod = ClassInsideStaticMethod.class; | |
/*Ignore*/ anonymousClassInsideStaticMethod = anonymousClassObj3.getClass(); | |
} | |
/*Ignore*/ static { staticMethod(); } | |
void nonStaticMethod () { | |
class ClassInsideNonStaticMethod {} | |
AnInterface anonymousClassObj4 = new AnInterface() {}; //anonymous class | |
/*Ignore*/ classInsideNonStaticMethod = ClassInsideNonStaticMethod.class; | |
/*Ignore*/ anonymousClassInsideNonStaticMethod = anonymousClassObj4.getClass(); | |
} | |
/*Ignore*/ static { new TopLevelClass().nonStaticMethod(); } | |
/*Ignore*/ public static Class classInsideStaticBlock; | |
/*Ignore*/ public static Class anonymousClassInsideStaticBlock; | |
/*Ignore*/ public static Class classInsideStaticMethod; | |
/*Ignore*/ public static Class anonymousClassInsideStaticMethod; | |
/*Ignore*/ public static Class classInsideNonStaticMethod; | |
/*Ignore*/ public static Class anonymousClassInsideNonStaticMethod; | |
} |
And then I create following Test Runner sort-of a class which basically access different nested test classes created inside the top level class above and to display their information for our analysis.
/** | |
* No-Arguments Default Constructor and Nested Classes (Non-Static Inner Class, Local Class, Anonymous Class) | |
* http://codeoftheday.blogspot.com/2013/07/no-arguments-default-constructor-and.html | |
*/ | |
package com.smhumayun.codeoftheday.NestedClassesExample; | |
import java.lang.reflect.Constructor; | |
import static com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass.*; | |
public class Test { | |
public static void main(String[] args) { | |
displayClassInfo("Top Level Class", TopLevelClass.class); | |
displayClassInfo("Static Nested Class", StaticClassInsideTopLevelClass.class); | |
displayClassInfo("Inner Class or Non Static Nested Class", TopLevelClass.NonStaticClassInsideTopLevelClass.class); | |
displayClassInfo("Anonymous Class inside Top Level Class", new TopLevelClass().anonymousClassObj1.getClass()); | |
displayClassInfo("Class inside static block", classInsideStaticBlock); | |
displayClassInfo("Anonymous Class inside static block", anonymousClassInsideStaticBlock); | |
displayClassInfo("Class inside static method", classInsideStaticMethod); | |
displayClassInfo("Anonymous Class inside static method", anonymousClassInsideStaticMethod); | |
displayClassInfo("Class inside non static method", classInsideNonStaticMethod); | |
displayClassInfo("Anonymous Class inside non static method", anonymousClassInsideNonStaticMethod); | |
} | |
static void displayClassInfo (String classInfo, Class clazz) { | |
StringBuilder sb = new StringBuilder("\n").append(classInfo) | |
.append("\n\t").append(clazz.getName()).append(" [ ") | |
.append(clazz.isMemberClass() ? "Member Class " : "") | |
.append(clazz.isLocalClass() ? "Local Class " : "") | |
.append(clazz.isAnonymousClass() ? "Anonymous Class " : "") | |
.append(clazz.isSynthetic() ? "Synthetic Class " : "") | |
.append("]") | |
.append(clazz.getDeclaringClass() != null ? "\n\tDeclared by class - " + clazz.getDeclaringClass().getSimpleName() : "") | |
.append(clazz.getEnclosingClass() != null ? "\n\tEnclosed in class - " + clazz.getEnclosingClass().getSimpleName() : "") | |
.append(clazz.getEnclosingConstructor() != null ? "\n\tEnclosed in constructor - " + clazz.getEnclosingConstructor().toGenericString() : "") | |
.append(clazz.getEnclosingMethod() != null ? "\n\tEnclosed in method - " + clazz.getEnclosingMethod().toGenericString() : "") | |
.append("\n\tConstructors:") | |
; | |
Constructor<?>[] constructors = clazz.getDeclaredConstructors(); | |
for (Constructor<?> constructor : constructors) { | |
sb.append("\n\t\t").append(constructor.toGenericString()); | |
} | |
System.out.println(sb); | |
} | |
} |
When you run the Test class, following output will be displayed on your console:
# No-Arguments Default Constructor and Nested Classes (Non-Static Inner Class, Local Class, Anonymous Class) | |
# http://codeoftheday.blogspot.com/2013/07/no-arguments-default-constructor-and.html | |
Top Level Class | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass [ ] | |
Constructors: | |
public com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass() | |
Static Nested Class | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$StaticClassInsideTopLevelClass [ Member Class ] | |
Declared by class - TopLevelClass | |
Enclosed in class - TopLevelClass | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$StaticClassInsideTopLevelClass() | |
Inner Class or Non Static Nested Class | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$NonStaticClassInsideTopLevelClass [ Member Class ] | |
Declared by class - TopLevelClass | |
Enclosed in class - TopLevelClass | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$NonStaticClassInsideTopLevelClass(com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass) | |
Anonymous Class inside Top Level Class | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$1 [ Anonymous Class ] | |
Enclosed in class - TopLevelClass | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$1(com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass) | |
Class inside static block | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$1ClassInsideStaticBlock [ Local Class ] | |
Enclosed in class - TopLevelClass | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$1ClassInsideStaticBlock() | |
Anonymous Class inside static block | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$2 [ Anonymous Class ] | |
Enclosed in class - TopLevelClass | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$2() | |
Class inside static method | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$1ClassInsideStaticMethod [ Local Class ] | |
Enclosed in class - TopLevelClass | |
Enclosed in method - static void com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass.staticMethod() | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$1ClassInsideStaticMethod() | |
Anonymous Class inside static method | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$3 [ Anonymous Class ] | |
Enclosed in class - TopLevelClass | |
Enclosed in method - static void com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass.staticMethod() | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$3() | |
Class inside non static method | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$1ClassInsideNonStaticMethod [ Local Class ] | |
Enclosed in class - TopLevelClass | |
Enclosed in method - void com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass.nonStaticMethod() | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$1ClassInsideNonStaticMethod(com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass) | |
Anonymous Class inside non static method | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$4 [ Anonymous Class ] | |
Enclosed in class - TopLevelClass | |
Enclosed in method - void com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass.nonStaticMethod() | |
Constructors: | |
com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass$4(com.smhumayun.codeoftheday.NestedClassesExample.TopLevelClass) |
Note following interesting observations:
- All nested classes, regardless of their type mentioned above, are mechanically generated by the compiler and hence a “$” in their fully qualified names. [Java Language Specification 3.8]
- Among all nested classes, static nested class is the only one that “retains” its constructor’s original signatures in the original form. All the other nested classes “looses” their constructor’s original signatures.
- For all the nested classes, other than the static nested class, following is true:
- If your nested class has no constructors defined, then don’t expect the default no-argument constructor to be available in these classes.
- If you nested class has one or more constructors defined, then don’t expect them to “retain” their original constructor signatures after compilation or at runtime.
- Why? because, java compiler, when compiles these nested classes, it “adds” an additional parameter at the very first (0 – zero) index of ALL constructors of a nested class. This additional parameter is actually the enclosing object’s reference. [Java Language Specification 8.1.3]
Now, if you refer to your Java Bean definition:
JavaBeans are are classes that are (1) serializable, (2) have a 0-argument constructor, and (3) allow access to properties using getter and setter methods.
So, by definition, all your non-static inner classes, local classes and anonymous classes disqualifies as JavaBeans.