Java Nested Class
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}1. Static Nested Class
Intuition:
Just like a top level class, nested for packaging convenience.Constructor:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
Consequences:
Enclosing Class Access:Can only direct access outer class static members. (Like any other class accessing OuterClass.java)
Members:
Can define both static/non-static members. (members: fields + methods.)
Usage:
//like top-level class, more power to define, less power to access
static class StaticNestedClass {
private Integer instanceField = 1;
private static String staticField = outer_static_field;
public static void staticMethod() {
String a = outer_static_field;
}
public void instanceMethod() {
String a = outer_static_field;
//String b = outer_instance_field; //ERROR: cannot reference non-static field
}
}
2. Inner Class
Intuition:
Like a instance member, "belongs to" an outer class instance.Constructor:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();Consequences:
Enclosing Class Access:
Direct access to all outer class members. Just like any method in outer class.
Members:
Can NOT define any static members. Since it is associated with an instance.
Usage:
//Like a instance member, "belongs to" an outer class instance.
class InnerClass {
private String inner_instance_field = "inner_instance_field";
public InnerClass () {}
public void get_outer_member () { //can access any outer member
String a = outer_static_field;
String b = outer_private_static_method();
String c = outer_instance_field;
inner_instance_field = "";
}
//COMPILE ERROR: no static member allowed
//public interface inner_interface {}; //an interface is an effective static member
//public static String get_static_instance_field () {}
//private static String static_field = "static_field";
}
2.1. Local Class
Intuition:
Defined inside a block (a method, a if block, a for loop). The scope of the class is its enclosing block.A special case of inner class. Thus no static member, a rule inherited from inner class.
Constructor:
Consequences:
Enclosing Class Access:Direct access to all outer class members. Just like any method in outer class.
But for local classes in static contexts, can only refer to static members of the enclosing class. "Non-static member cannot be referenced from a static context" this rule always applies.
Members:
Can NOT define any static members. EVEN IF it's inside a static block.
Only exception is for static final String/primitive. As they are stored like a constant.
A local class can have static members provided that they are constant variables.
(A constant variable is a variable of primitive type or type String that is declared
final and initialized with a compile-time constant expression.
A compile-time constant expression is typically a string or an arithmetic expression
that can be evaluated at compile time.
Note: If a primitive type or a string is defined as a constant and the value is known at
compile time, the compiler replaces the constant name everywhere in the code with its value.
This is called a compile-time constant. If the value of the constant in the outside world changes
(for example, if it is legislated that pi actually should be 3.975),
you will need to recompile any classes that use this constant to get the current value.
Local Variable Access:
Can access local variables or method parameters that is final.
A local class can use the local variables, method parameters,Usage:
and even exception parameters that are in its scope,
but only if those variables or parameters are declared final.
This is because the lifetime of an instance of a local class can be
much longer than the execution of the method in which the class is defined.
For this reason, a local class must have a private internal copy of
all local variables it uses (these copies are automatically generated by the compiler).
The only way to ensure that the local variable and the private copy
are always the same is to insist that the local variable is final.
{
class LocalClass {
//can access outer member
String a = outer_instance_field;
String b = outer_static_field;
//static String c = ""; //ERROR: no static allowed
//final static String d ; //ERROR: not a compile-time constant
final static String d = ""; //a constant known at compile time
}
//static class StaticLocalClass {} //ERROR: local class cannot be static, regardless where.
}
static { //this is a static context
//static class StaticLocalClass {} //ERROR: local class cannot be static, even if in static context
class LocalClass {
//can access outer member
//String a = outer_instance_field; //ERROR: non-static cannot be referenced from static context
String b = outer_static_field;
//static String c = ""; //ERROR: no static allowed
//final static String d ; //ERROR: not a compile-time constant
final static String d = ""; //a constant known at compile time
}
}
public void outer_instance_method(Object method_param) {
String outer_instance_method_local_var = "";
class LocalClass { //local class at non-static context
String f = ""; //can have non-static member
/*
A local class can have static members provided that they are constant variables.
(A constant variable is a variable of primitive type or type String that is declared
final and initialized with a compile-time constant expression.
A compile-time constant expression is typically a string or an arithmetic expression
that can be evaluated at compile time.
Note: If a primitive type or a string is defined as a constant and the value is known at
compile time, the compiler replaces the constant name everywhere in the code with its value.
This is called a compile-time constant. If the value of the constant in the outside world changes
(for example, if it is legislated that pi actually should be 3.975),
you will need to recompile any classes that use this constant to get the current value.
*/
//final static Object d = new NestedClassTest(); //ERROR: this is not a compile time constant
final static int e = 5; //need to be string or int. need to know it at compile time
String a = outer_instance_field;
String b = outer_static_field;
String c = outer_instance_method_local_var; //outer_instance_method_local_var need to be final
Object abc = method_param; //can access final method param
private void local_method() {
Object d = method_param; //can access final method param
//outer_instance_method_local_var = ""; //ERROR: need to be final
//method_param = ""; //ERROR: need to be final
outer_instance_field = ""; //no problem interact with outer class field
outer_static_field = ""; //can access static or non-static
LocalClass a = new LocalClass();
}
}
//a local class is valid only within the scope defined by its enclosing block.
//But the local class has access to outer class members.
LocalClass a = new LocalClass();
/*
A local class can use the local variables, method parameters,
and even exception parameters that are in its scope,
but only if those variables or parameters are declared final.
This is because the lifetime of an instance of a local class can be
much longer than the execution of the method in which the class is defined.
For this reason, a local class must have a private internal copy of
all local variables it uses (these copies are automatically generated by the compiler).
The only way to ensure that the local variable and the private copy
are always the same is to insist that the local variable is final.
*/
outer_static_field2 = a; //here, a local class instance outlives local method scope
a.local_method();
}
2.2. Anonymous Class
Intuition:
Local class without a name.Constructor:
//implementing interfaceConsequences:
new InterfacName () { /*class-body*/ }
//extending class
new ClassName ( [ argument-list ] ) { /*class-body*/ }
Enclosing Class Access:
Direct access to all outer class members. Just like local class.
Members:
Can NOT define any static members.
Only exception is for static final String/primitive. As they are stored like a constant.
Local Variable Access:
Can access local variables or method parameters that is final.
Usage:
class Executor {public static void execute(Runnable r){r.run();r.run2();}}
class BaseTracker {public void track(Object obj){}}
interface Runnable {
void run(); //abstract method
default void run2(){}; //extension method
}
class Tracker extends BaseTracker{
private String outer_class_var = "";
//anonymous class
public void track1(final Object event) {
Executor.execute(new Runnable() {
//static String a = ""; //ERROR: no static allowed
final static String b = ""; //constant OK
String c = outer_class_var; //compiler create a package-level getter for enclosing class's private variables
@Override
public void run() {
Tracker.super.track(event); //Tracker.super refers to enclosing class's super class
//super.track(event); //ERROR: cannot resolve
//BaseTracker.track(event); //ERROR: can only reference static method
}
});
}
//local class
public void track2(final Object event) {
//anonymous class translated into local class
class TrackerRunnable implements Runnable {
//@Override
public void run(){
//super need to be in a non-static context
System.out.println(this.toString()); //this refers to the TrackerRunnable instance
System.out.println(super.toString()); //super defaults to the same instance!!!
Tracker.super.track(event); //Tracker.super refers to BaseTracker
Runnable.super.run2(); //Runnable.super refers to Runnable
//super.track(event); //ERROR: cannot resolve, super refers to this
//BaseTracker.track(event); //ERROR: can only reference static method, .track() is instance method
}
}
Executor.execute(new TrackerRunnable());
}
public static void main(String... args) {
new Tracker().track2("");
}
}
Reference: Java in a Nutshell: How Inner Classes WorkTODO: final keyword:
1. class - cannot be subclassed
2. method - cannot be overridden
3. variable - cannot be assigned more than once
Java memory model: stack, heap,
synthetic copy
dp/dip 是个长度单位。