Java内部类使用总结

Categories: Java; Tagged with: ; @ February 13th, 2009 20:44

顶层类只能处于Public跟默认访问级别. 而内部类可以处于任意访问级别.

A 实例内部类:

  • 在创建实例内部类实例时, 外部类的实力必须已经存在.
  • 实例内部类自动持有外部类实例的引用
  • 一个外部类可以有多个内部类 因此不允许外部类直接调用内部类方法或属性. 而内部类进对应一个外部类, 因此可以直接使用外部类的引用.
  • 在实例内部类中不能定义静态成员, 只能定义实例成员.
  • 当内部类与外部类有同名的成员时,如age, 在内部类中直接使用age或this.age表示inner2内age 而OnlyForTest.this.age表示外部类中的age.

B 静态内部类:

  • 静态内部类的实例不会自动持有外部类的特定实例的引用, 因此在创建内部类的实例时, 不必创建外部类的实例.
  • 静态内部类可以直接访问外部类的静态成员, 如果要访问外部类的实例成员, 就必须通过外部类的实例去访问
  • 静态内部类中可以定义静态成员和实例成员
  • 客户类可以通过完整的类名直接访问静态内部类的静态成员.

局部内部类:

  • 与局部变量一样, 不能被访问控制符修饰.
  • 只能在当前方法中使用
  • 不能包含静态成员
  • 在局部类中定义的内部类也不能被访问控制符修饰
  • 局部内部类和实例内部类一样, 可以访问外部类的所有成员, 此外, 局部内部类还可以访问所在方法中的final类型的参数和变量.

匿名类:

  • 匿名类没有构造方法, 但是会调用父类的构造方法.
  • 匿名类尽管没有构造方法, 但是可以在匿名类中提供一段实例初始化代码
  • 除了可以在外部类的方法内定义匿名类之外, 还可以在生命一个成员变量时定义匿名类
  • 匿名类除了可以继承外, 还可以实现接口
  • 匿名类和局部内部类一样, 都可以访问外部类的所有成员, 如果匿名类位于一个方法中, 还可以访问方法内部的final类型的变量和参数

 

举例[实例内部类, 静态内部类]:

 

public class OnlyForTest {
	public static String staticOutMember = "Static Out Member";
	private String userName;
	private int age;
	//省略Getter/Setter
	
	public static void main(String[] args) {
		OnlyForTest oft = new OnlyForTest();
		//A1. 在创建实例内部类实例时, 外部类的实力必须已经存在.
		OnlyForTest.Inner inner = oft.new Inner();
		
		//A3. 一个外部类可以有多个内部类  因此不允许外部类直接调用内部类方法或属性, 在需要时, 使用内部类实例访问内部类成员
		//而内部类进对应一个外部类, 因此可以直接使用外部类的引用.
		oft.age = oft.new Inner2().age;
		
		inner.setOutInstanceNmae("tom");
		
		oft.new Inner2().print();
		
		//B1: 直接访问静态类静态成员, 不需创建实例.
		System.out.println(staticInnerClass.staticInnerMember);
		
		new staticInnerClass().printNmae();
	}
	
	class Inner {
		public void setOutInstanceNmae(String s){
			//A2. 实例内部类自动持有外部类实例的引用
			userName = s;
			System.out.println("内部类直接引用外部类实例 - 内部类赋值外部类成员 " + userName);
		}
	}//end of class Inner
	
	class Inner2 {
		int age= 2;
		//A4. 在实例内部类中不能定义静态成员, 只能定义实例成员.
		//报错!static int staticInt = 4;
		public void print() {
			System.out.println(userName);
			//A5. 当内部类与外部类有同名的成员时,如age
			//直接使用age或shis.age表示inner2内age
			//OnlyForTest.this.age表示外部类中的age
			System.out.println(age);
			System.out.println(OnlyForTest.this.age);
			//B2. 直接访问外部类的静态成员
			System.out.println(staticOutMember);
		}
	}//end of class Inner2
	
	static class staticInnerClass {
		public static String staticInnerMember = "Static Inner Member";
		public void printNmae() {
			//B3:静态内部类在访问外部类实例变量时, 必须通过外部实例
			OnlyForTest o = new OnlyForTest();
			o.userName = "set by Static Inner Class";
			System.out.println(o.userName);
		}
	}//end of staticInnerClass
}

编译后的Class文件:

image

DeCompiler之后 Inner的构造函数:

    OnlyForTest$Inner2()
    {
        this$0 = OnlyForTest.this;
        super();
        age = 2;
    }

可见, 每个inner实例都会自动包含一个外部类OnlyForTest的引用

而staticInnerClass类的构造函数为空, 因此他的实例不会自动引用外部类

从Decompile的Class文件来看, 对JVM来说, 无所谓内外类之分, 他们都是Class, 只是内部类会自动引用外部类实例 或是 其他特定的功能而已.



// Proudly powered by Apache, PHP, MySQL, WordPress, Bootstrap, etc,.