Java内部类



内部类(inner class)是定义在另一个类中的类。为什么需要使用内部类呢?其主要原因有以下三点:

  • 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。

  • 内部类可以对同一个包中的其他类隐藏起来。

  • 当想要定义一个回调函数且不想编写大量代码时,使用匿名(anonymous)内部类比较便捷。

内部类可以分为:

  • 成员内部类

  • 局部内部类

  • 静态内部类

  • 匿名内部类

1.成员内部类

成员内部类:就是在外部类的内部再定义一个类

public class OuterClass1 {
	private int i = 10;
	private int j = 20;
	private static int count = 0;
	public static void func1(){}
	public static void func2(){}
	//成员内部类中,不能定义静态成员
	//成员内部类中,可以访问外部类中的所有成员
	class InnerClass {
		//内部类中不允许定义静态变量
		//static int inner i = 100;
		int j = 100;//内部类和外部类的实例变量可以共存
		int k = 1;
		void innerFunc1(){
			System.out.println("内部类中k值为" + k);
			//在内部类中访问内部类自己的变量直接用变量名
			System.out.println("内部类中j值为" + j);
			//在内部类中访问自己的变量名也可以用this.变量名
			System.out.println("内部类中j值为" + this.j);
			//在内部类中访问外部类与内部类重名的实例变量用“外部类名.this.变量名”
			System.out.println("外部类中j值为" + OuterClass1.this.j);
			//如果内部类中没有与外部类同名的变量,则可以直接用变量名访问外部类变量
			System.out.println("外部类中count值为:" + count);
			func1();
			func2();
		}
	}
	//外部类的非晶态方法访问成员内部类
	public void func3(){
		InnerClass inner = new InnerClass();
		inner.innerFunc1();
	}
	public static void main(String[] args) {
		//内部类的创建原则是,首先创建外部类对象,然后通过此类创建内部类对象
		//静态的内部类则不需要外部类对象的引用
		OuterClass1 out = new OuterClass1();
		OuterClass1.InnerClass outin1 = out.new InnerClass();
		outin1.innerFunc1();
		//也可以将创建代码合并在一块
		OuterClass1.InnerClass outin2 = new OuterClass1().new InnerClass();
		outin2.innerFunc1();
	}
}

2.局部内部类

局部内部类不能用publicprivate访问说明符进行声明。它的作用域被限定在声明这个局部类的块中。

局部类有一个优势,即对外部世界可以完全地隐藏起来。即使所在外部类的其他代码也不能访问它

与其他内部类相比较,局部类还有一个优点。它们不仅能够访问包含他们的外部类,还可以访问局部变量。不过,那些局部变量必须被声明为final

public class OutClass2 {
	private int s = 10;
	private int k = 0;
	public void func1(){
		final int s= 20;
		final int j= 1;
		//局部内部类
		class InnerClass{
			int s = 30;//可以定与外部类同名的变量
			//static int m = 20;//不可以定义静态变量
			void innerFunc(){
				//如果内部类没有与外部类同名的变量,在内部类中可以直接访问外部类的实例变量
				System.out.println("外围类成员" + k);
				//可以访问外部类的局部变量(即方法内的变量),但是必须声明为final
				System.out.println("常量:" + j);
				//如果内部类中有与外部类同名的变量,直接访问的是内部类中的变量
				System.out.println("常量:" + s);
				//用this.变量名访问的也是内部类的变量
				System.out.println("常量:" + this.s);
				//用外部类名this.内部变量名访问的是外部变量
				System.out.println("外部变量成员:" + OutClass2.this.s);
			}
		}
		new InnerClass().innerFunc();
	}
	public static void main(String[] args) {
		//访问局部内部类必须先定义外部类对象
		OutClass2 out = new OutClass2();
		out.func1();
	}
}

3.静态内部类

/**
 * 静态内部类
 * 静态内部类可以用public、protected、private修饰,
 * 不能从嵌套类的对象中访问非静态类的外围对象
 * 静态内部类与普通内部类的区别:
 * 1.静态内部类:内部类对象可以与外部类对象没有联系,在静态内部类中不能访问外部类的非静态成员
 * 2.普通内部类:对象隐含的保存了一个引用,指向创建他的外围类对象。
 * */
public class OutClass3{
	public static int i = 1;
	public int j = 10;
	public static void func1(){
		
	}
	public void func2(){
		
	}
	//静态内部类可以用static、public、private修饰
	//静态内部类中可以定义静态或非静态的成员
	static class InnerClass{
		static int inner_i = 100;
		int inner_j = 200;
		static void innerFunc1(){
			//静态内部类只能访问外部类的静态成员(包括静态变量和静态方法)
			System.out.println("outer.i" + i);
			func1();
		}
		void innerFunc2(){
			//静态内部类不能访问外部类的非静态成员(包括非静态变量和非静态方法)
//		System.out.println("outer.j" + j);		
			//func2();
		}
	}
	public static void func3(){
		//外部类访问内部类的非静态成员:实例化内部类即可
		InnerClass inner =new  InnerClass();
		inner.innerFunc1();
	}
	public static void main(String[] args) {
		new OutClass3().func3();
		//静态内部类的对象可以直接生成
		OutClass3.InnerClass inner = new OutClass3.InnerClass();
		inner.innerFunc2();
	}
}

有时候,使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象。为此,可以将内部类声明为static,以便取消产生的引用。

注释:声明在接口中的内部类自动成为staticpublic类。

4.匿名内部类

假如一个类只有在当前方法中使用一次,只创建这个类的一个对象,就不必命名了。这种类被称为匿名内部类(anonymous)。

public void start(int interval , final boolean beep){
		ActionListener listener = new TimerPrinter()
		{
			public void actionPerformed(ActionEvent e){
				Date date = new Date();
				SimpleDateFormat f = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
				System.out.println("现在时间:" + f.format(date));
				if(beep)Toolkit.getDefaultToolkit().beep();
			}
		};
		Timer t = new Timer(interval , listener);
		t.start();
	}
它的含义是:创建一个实现 ActionListener 接口的类的新对象,需要实现的方法 actionPerformed 定义在括号 {} 内。

通常的语法格式为:

new SuperType(Constructionparameters)

{

       inner class methods and data

}

其中,SuperType可以使接口,于是内部类就要实现这个接口;也可以是一个类,于是内部类就要扩展它。

由于构造器的名字必须与类名相同,而匿名类没有类名,所以,匿名类不能有构造器。取而代之的是,将构造器参数传递给超类构造器。尤其是在内部类实现接口的时候,不能有任何构造参数。不仅如此,还要提供一对花括号。

注释:下面的技巧称为双括号初始化double braceinitialization),这里利用了内部类语法。假设想构造一个数组列表,并将它传递到一个方法:

ArrayList<String> strs = new ArrayList<String>();
		strs.add("STR1");
		strs.add("STR2");
		strs.add("STR3");

如果不再需要这个数组列表,最好让它作为一个匿名列表。

ArrayList<String> sts = new ArrayList<String>(){{add("a");add("b");}};

你可能感兴趣的:(Java内部类)