嵌套类有四种:静态成员类、非静态成员类、匿名类、局部类。
除了第一种之外,其他三种都是内部类。(EffectiveJava,Item22)
静态成员类(static member class)
静态成员类可以看作是一个普通的类,只是碰巧声明在另一个类的内部而已。
使用static修饰的嵌套类称之为静态成员类,它只能访问外部类的静态成员,不能直接访问外部类的非静态成员。
在静态成员类, 不能访问外部类的非静态成员, 这是由Java语法中"静态方法不能直接访问非静态成员"所限定。
对于外部类来说,整个静态内部类就是外部类成员。类成员只能不能访问类对象属性或方法。
package vlis.myfly.test;
public class StaticMemberClassDemo {
private int a = 1;
private int e = 5;
private static int b = 2;
public void execute(){
//在外部类中创建成员内部类
StaticMemberClass staticMemberClass = new StaticMemberClass();
staticMemberClass.execute();
//不能直接访问内部类成员,包括了非静态成员和静态成员
//System.out.println(c);
//System.out.println(d);
System.out.println(staticMemberClass.c);
System.out.println(StaticMemberClass.d);
}
private static class StaticMemberClass{// 静态内部类可以用public,protected,private修饰
//内部类可以创建与外部类同名的成员变量
private int a = 1;
private int c = 3;
private static int b = 2;
private static int d = 4;
public void execute(){
//this引用的是内部类
System.out.println(this.a);
//在静态内部类中,可以访问到外部类的静态成员
System.out.println(StaticMemberClassDemo.b);
//不能直接访问外部类的非静态变量
//System.out.println(e);
StaticMemberClassDemo staticInner = new StaticMemberClassDemo();
System.out.println(staticInner);
System.out.println(staticInner.e);
}
}
public static void main(String[] args){
StaticMemberClassDemo demo = new StaticMemberClassDemo();
System.out.println(demo);
demo.execute();
}
}
非静态成员类(nonstatic member class)
- 非静态成员类必须依赖于外部类的对象;
- 在非静态成员类中无法定义静态成员;
- 非静态成员类对象隐含地保存了一个引用,指向创建它的外部类对象(代码示例中的NonStaticMemberClass.this);
- 非静态成员类的实例被创建的时候,它和外围实例时间的关联关系也随之被建立起来,而且,这种关联关系以后不能被修改。这种关联关系需要消耗非静态成员类实例的空间,并且增加了构造的时间开销。
Map接口的实现往往使用非静态成员类来实现他的集合视图;Set和List这种集合接口的实现也使用非静态成员类来实现他们的迭代器。
package vlis.myfly.test;
public class NonStaticMemberClassDemo{
private int a = 1;
static int b = 2;
public void execute(){
//在外部类中创建成员内部类
NonStaticMemberClass nonStaticMemberClass = this.new NonStaticMemberClass();
nonStaticMemberClass.execute();
}
public class NonStaticMemberClass{
//内部类可以创建与外部类同名的成员变量
private int a = 2;
//NOTE:在非静态内部类中,不能创建静态成员
public void execute(){
//this引用的是内部类
System.out.println(this.a);
//在非静态内部类中使用外部类的成员变量的方法(MemberInner.this.a)
//在非静态内部类中,可以访问到外部类的私有成员
System.out.println(NonStaticMemberClassDemo.this.a);
//在非静态内部类中,可以访问到外部类的静态成员
System.out.println(NonStaticMemberClassDemo.b);
}
}
public static void main(String[] args){
NonStaticMemberClassDemo demo = new NonStaticMemberClassDemo();
demo.execute();
}
}
静态内部类与非静态内部类的区别
一 . 静态内部类可以有静态成员,而非静态内部类则不能有静态成员。
二 . 静态成员类的非静态成员可以访问外部类的静态变量,而不可访问外部类的非静态变量;
三 . 非静态成员类的实例方法内部,可以调用外围实例上的方法和属性。
如果声明成员类不要求访问外围实例,就要始终把static修饰符放在它的声明中,使它成为静态成员类,而不是非静态成员类。如果省略了static修饰符,则每个实例都会包含一个额外的指向外围对象的引用。这不仅消耗空间和时间,并且会导致外围实例在符合垃圾回收时却仍然保留。(比如HashMap中的Entry静态成员类)
匿名类
匿名类没有名字。它不是外围类的一个成员。它并不与其他的成员一起被声明,而是在使用的同时被声明和实例化。
当且仅当匿名类出现在非静态的环境中时,它才有外围实例。当时即使它出现在静态的环境中,也不可能拥有任何静态成员。
匿名类常见用法:动态的常见函数对象(EffectiveJava,Item21),例如事件监听器;创建过程对象,比如Runnable、Thread或者TimerTask。还有就是静态工厂方法内部,ruturn new XXX();(EffectiveJava,Item18)
局部类
在任何可以声明局部变量的地方,都可以声明局部类,并且局部类也遵守同样的作用域规则。
和匿名类一样,匿名类出现在非静态的环境中时,它才有外围实例。当时即使它出现在静态的环境中,也不可能拥有任何静态成员。
总结:
非静态成员类和静态成员类的使用在于是否每一个嵌套类实例都需要指向其外围实例的引用。
如果一个嵌套类属于一个方法的内部,如果只需要在一个地方创建实例,并且已经有一个预置的类型可以说明这个类的特征,就使用匿名类,否则,使用局部类。
还有一个比较常见的嵌套枚举类