内部类:Core Java 6.4

如果一个类定义在另一个类的内部,这个类就是内部类。

为什么要用内部类,什么场景下需要用内部类

  1. 根据面向对象设计原则,需要定义一个新的类,并对相关操作和属性进行封装。

  2. 新类仅同另一个类有密切依赖关系或者逻辑关系,其它类基本不会用到它;或者这个新的类仅是为了另一个类提供服务。

  3. 当发现一个类需要继承一个以上的类时,此时需要检查一下此类是否符合类的单一功能原则,是否应该定义新的类,是否需要定义一个内部类来继承另外的类,同时也能实现功能需求。

  4. 需要对一个抽象类或者接口做具体实现,但是这个实现只有一个地方会调用他,此时没必要专门定义一个单独的类,可以用局部内部类或者匿名内部类。

内部类的优点

  1. 内部类继承的类和外部类继承的类不同,这样对于外部类来说,变相的实现了多继承功能。

  2. 方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。

  3. 相对于直接将内部类的功能揉在外部类中——即不定义一个新的内部类——来说,定义一个内部类也能更充分利用JIT的优化功能,也更符合类的单一功能设计原则。

  4. 方便编写事件驱动程序

内部类的语法规则

内部类分为四种:成员内部、局部内部类、匿名内部类、静态内部类。

常规内部类 / 成员内部类

可以将成员内部类当做外部类的一个成员,与外部类的实例域和成员方法是同级的,是与外部类的实例域和成员方法的地位相同的存在。因此:

同实例域一样,成员内部类也可以声明为private的,也只有内部类可以声明为private。成员内部类的访问控制也同外部类的实例域相同。

同成员方法类似,成员内部类中不允许定义静态成员,即不能有静态变量和静态方法。

同外部类的成员方法一样,内部类可以直接访问其所在外部类内的其它成员,包括域和方法。可以显示地通过outer.fieldName | outer.method(),也可以不用outer而直接访问。

当在另外的类中构造内部类的实例时,首先要有一个外部类的实例对象outer。

public class Test{
	public static void main(String [] args){
		Outer outer = new Outer();
		Outer.Inner inner = outer.new Inner();
	}
}
public class Outer{
	public class Inner{
		
	}
}

当在外部类中调用成员内部类的方法时,需要遵循一般类的访问控制规则,如果内部类中的成员为private时,外部类是没有访问权限的。

常规内部类的对象inner会持有外围类对象outer的引用。因为编译器在编译阶段会自动改造内部类的构造方法——不论内部类的构造方法是否有显式的定义,都会对构造方法添加一个参数outer,并将此参数声明为改造后的构造方法的第一个参数。
而常规内部类的创建上也可以体现这一点:

public class Test{
	public static void main(){
		Outer outer = new Outer();
		Inner inner = outer.new Inner();
		outer.outerM1();
		inner.innerM2();
	}
}

public class Outer{

	private String outerStr;
	
	public void outerM1(){
		new Inner().innerM2();
	}

	// 成员内部类,地位等同于所在外部类的实例域和成员方法,访问控制符的对成员内部类的作用也与他们相同
	class Inner{ //如果声明为private,那么除其所在外部类外其它类无法访问,一般情况下会定义为private。
		// 成员内部类中定义的实例域和方法,其访问权限同普通类内的实例域和成员方法一样。
		private String innerStr;
		public Inner(){  		
		}
		
		//可以直接访问外部类中的实例域、直接调用外部类中的方法。
		public void innerM1(){
			outerM2();
		}

		public void innerM2(){
			outerStr="outerStrByInnerM2";
		}
	}
}

局部内部类

在方法或者代码块中定义的类,如同方法内部的局部变量一样。
其可见性也只在所在代码块内。

public class Outer{

    public static void main(String[] args){
	  new Outer().outerM1();
    }
    
	public void outerM1(){
		// 局部内部类
		class LocalInner
		{
			public void innerM1(){
				System.out.println(" innerM1");
			}
		}
		// 实例化并调用方法
		new LocalInner().innerM1();
	
	}
}
 

匿名内部类

匿名内部类也是定义在代码块中的类,但是没有显式地声明类的名称。一般是对接口的实现或者类的继承,在定义的同时会直接实例化出一个对象并调用方法。线程的创建和使用是最常见使用匿名内部类的场景。

public class Test{


    public static void main(String[] args){
	  new Test().m1();
    }
    
	public void m1(){

		new Thread(

			new Runnable(){

				public void run(){

					try{
						Thread.sleep(1000);
						System.out.println("thread end");
					} catch (InterruptedException e){
						e.printStackTrace();
					}
				}

			}

		).start();
		
	}

}

静态内部类

在内部类不需要访问外围类对象的时候,应该使用静态内部类。也可以称静态内部类为嵌套类(nested class)。
静态内部类只能访问外部类的静态成员。
单例模式可以用静态内部类实现。

public class Singleton{

	// 利用JVM自身的类加载和初始化机制,既能确保单例,又能确保实例只在需要的时候被初始化
	// 加载,链接(校验、准备、解析),初始化(只在用户程序主动调用时发生) 
	private static class InstanceHolder{
		public static final Singleton INSTANCE = new Singleton();
		
	}
	
	// 构造函数私有化
	private Singleton(){}
	
	// 对外提供一个获取单例的方法
	public static Singleton getInstance(){
		return InstanceHolder.INSTANCE ;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章