内部类的细节、规则挺多的内部类一般可分为4中:regular inner class, static inner class, method-local inner class, and anonymous inner class(AIC).
We use the term regular here to represent inner classes that are not statci, method-local, and AIC.
1. Regular Inner Class
(1)The only way you can access the inner class isthrough a live instance of the outer class! In other words, only at runtime when there's already an instance of the outer class to tie the inner class instance to.
To create an instance of an inner class, you musthave an instance of the outer class to tie to the inner class. There are no exceptions to this rule: an inner class instance can never stand alone without a direct relationship to an instance of the outer class.
(2)Inner classes have access rights to all the elements in the outer class. (Including all the four inner class types)
An typical example:
public class MyOuter {
private int x = 7; // private field
public void makeInner() {
MyInner in = new MyInner(); // make an inner instance
in.seeOuter();
}
class MyInner {
public MyInner() {
System.out.println("Inner class constructor");
}
public void seeOuter() {
System.out.println("Outer x is " + x); // can access any thing in outer class
System.out.println("Inner class ref is " + this); // Inner class this
System.out.println("Outer class ref is " + MyOuter.this); // Outer class this
}
}
public static void main(String[] args) {
MyOuter out = new MyOuter(); //instantiating the outer class, but now,
//the inner class has been not instantiated yet!
MyOuter.MyInner in = out.new MyInner();
in.seeOuter();
}
}
output:
Member Modifiers Applied to Inner Classes
A regular inner class is a member of the outer class just as instance variables and methods are, so the following modifiers CAN be applied to an inner class:
final
abstract
public
private
protected
static—but static turns it into a static nested class not an inner class
strictfp
2. Method-Local Inner Classes
Method-local classes are defined within a method.
An simple example:
class MyOuter2 {
private String x = "Outer2"; // private field
void doStuff() {
class MyInner {
public void seeOuter() {
System.out.println("Outer x is " + x);
}
}
MyInner mi = new MyInner(); // This line must come after the class
// different from regular inner class declaration
}
}
Very, very, very important rules:
(1)A method-local inner class can be instantiated only within the method where the inner class is defined.
(2)Like regular inner class objects, the method-local inner class object shares a special relationship with the enclosing (outer) class object, and can access its private (or any other) members. However,
(3)The method inner class object cannot use the local variables(or arguments) of the method the inner class is in. 这一条规则同样使用与匿名内部类!
Explanations and solutions to (3):
The local variables of the method live on the stack, and exist only for the lifetime of the method. You already know that the scope of a local variable is limited to the method the variable is declared in. When the method ends, the stack frame is blown away and the variable is history. But even after the method completes, the inner class object created within it might still be alive on the heap if, for example, a reference to it was passed into some other code and then stored in an instance variable. Because the local variables aren't guaranteed to be alive as long as the method-local inner class object, the inner class object can't use them.
Unless the local variables are marked final!
But why? Why marking the local variable asfinal would make a difference? Marking (an object reference )variable as final means that you can't assign another value to that variable, but it has no effect on the variable's scope.
Actually, the method local inner classgets a copy of the final variables of the enclosing(outer) method. There is no problem with this as we know that the value of final variables cannot be changed, so the copy of the final variable that the local class has is always same as the value of the final variable in the method. So when an instance of the method local inner class is created, it gets a copy of the final variables of the class which the method local inner class stores as instance fields. This is all hidden from us and is done automatically by the compiler...
Method-local classes and Anonymous inner classes require final variables because of the way they are implemented in Java. An anonymous inner class (AIC) uses local variables by creating a private instance field whichholds a copy of the value of the local variable. The inner class isn't actually using the local variable, but a copy.
It should be fairly obvious at this point that a "Bad Thing" can happen if either the original value or the copied value changes; there will be some unexpected data synchronization problems. In order to prevent this kind of problem, Java requires you to mark local variables that will be used by the AIC as final (i.e., unchangeable).
This guarantees that the inner class' copies of local variables will always match the actual values.
Yes, I understand, Thanks forJavaRanch!
Examples are shown after Anonumous Inner classes!
Loval variable modifiers aplpied to method-local inner classes
A method local class is a member of the method just as local variables are, so the following modifiers CAN be applied to an method locall inner class:
final
abstract
CAN'T be:
public, protected, private, static and so on,because local variables are not allowed to be these modifiers!
class MethodLocalClass {
public void testClass() {
final class InsideMethod1 { } // ok
protected class InsideMethod2 { }
// compiler error, can't have protected, public, private
// because local variabes can't be public, protect, and private
static class InsideMethod1 { } // compiler error
}
}

3. Anonymous Inner Classes
Anonymous inner class has no class name, so it has no constructor !
(1)Plain-Old Anonymous Inner Classes, Flavor One
class Popcorn {
public void pop() {
System.out.println("popcorn");
}
}
class Food {
Popcorn p = new Popcorn() { // This anonymous class is the subclass of Popcorn
public void pop() { // It is overriding method of super class Popcorn
System.out.println("anonymous popcorn");
}
};
}
Polymorphism is in play when anonymous inner classes are involved.
(2)Plain-Old Anonymous Inner Classes, Flavor Two
The only difference between flavor one and flavor two is that flavor one creates an anonymous subclass of the specified class type, whereas flavor two creates an anonymous implementer of the specified interface type.
interface Cookable {
public void cook();
}
class Food2 {
Cookable c = new Cookable() { // (A)implement interface Cookable
public void cook() { // must be implement all the methods of the interface
System.out.println("anonymous cookable implementer");
}
};
}
(A):
You can't instantiate an interface, yet that's what the code looks like it's doing. But of course it's not instantiating a Cookable object,it's creating an instance of a new, anonymous, implementer of Cookable. You can read this line:
Cookable c = new Cookable() {
as "Declare a reference variable of type Cookable that, obviously, will refer to an object from a class that implements the Cookable interface. But, oh yes, we don't yet have a class that implements Cookable, so we're going to make one right here, right now. We don't need a name for the class, but it will be a class that implements Cookable, and this curly brace starts the definition of the new implementing class."
(3)Oher Formal Anonymous Inner Classes and Examples
1)
class MyOuter3 {
private String x = "Outer2";
void doStuff(final int version) { // arguments are local variable, must be final here
String z = "local variable"; // must be final here
class MyInner {
public void seeOuter() {
System.out.println("Outer x is " + x);
System.out.println("Version is " + version); //require version must be final
System.out.println("Local variable is " + z);//require z must be final
}// public void seeOuter(
}// class MyInner {
}// void doStuff(
}
The inner class used the local variable version and z, so they must be final!
2)
interface Destination {
String readLabel(); // implicitly public abstract
}
public class Parcel {
public Destination getDestination(final String dest) { //variabe dest must be final
return new Destination() {
private String label = dest; // require dest must be final
public String readLabel() { // must be public
return label;
}
};
}
}
3)
You can not have a named constuctor in an anonymous class since there is no name, but, with instance initialization, you can, in effect, create a constructor for an anonymous inner class.
abstract class Base {
public Base(int i) {
System.out.println("Base constructor, i = " + i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i) {
return new Base(i) { // i is outside of anonymous inner class,
// so i need not to be final
{
System.out.println("Inside instance initializer");
}
public void f() {
System.out.println("In anonymous f()");
}
};
}
}
4. Static Nested Classes
We saved the easiest for last, as a kind of treat : )
You'll sometimes hear static nested classes referred to as static inner classes, but they really aren't inner classes at all, by the standard definition of an inner class.
A static nested class is simply a class that's just a static member of the enclosing(outer) class:
class BigOuter {
static class Nested { }
}
The class itself isn't really "static"; there's no such thing as a static class. The static modifier in this case says that the nested class isa static member of the outer class. That meansit can be accessed, as with other static members, without having an instance of the outer class.