Core Java (十六) 内部类

内部类,inner class,是定义在另一个类中的类。内部类是一种编译器现象,与虚拟机无关,编译器将会把内部类翻译成用$分隔外部类名与内部类名的常规类文件,而虚拟机对此一无所知。内部类比常规类更加强大,最大的特点是内部类可以访问外围类的私有数据。

非内部类的修饰符 only public, abstract & final are permitted,而内部类可以有private修饰。

内部类有三点原因被需要:

  1. 内部类可以访问该类定义所在的作用域中的数据,包括private类型的。
  2. 内部类可以对同一个包中的其他类隐藏起来。
  3. 当想要定义一个回调函数且不想编写大量代码的时候,使用匿名内部类比较便捷。

内部类的一般写法

下面的演示程序演示了使用内部类访问外部类的私有数据。

其中内部类Pair访问了外部类OuterClass的私有数据secret。最终在console输出100。

package com.xujin;

public class Test{
	public static void main(String...arg){
		OuterClass outerClass = new OuterClass();
		outerClass.setSecret(100);
		System.out.println(outerClass.getInfo());
	}	
}

class OuterClass{
	private int secret;
	
	public int getInfo(){
		Pair pair = new Pair();
		return pair.getSecret();
	}
	
	public void setSecret(int secret){
		this.secret = secret;
	}
	
	public class Pair{
		public Pair(){
			this.take = secret;
		}
		
		public int getSecret(){
			return this.take;
		}
		
		private int take;
	}
}

下面是编译完成之后的类文件:

Core Java (十六) 内部类_第1张图片

可见,内部类生成了名为OuterClass$Pair.class的文件。


为了能运行上面这个程序,内部类总有一个隐式引用,它指向了创建它的外部类对象。下面,我们将这个外部类对象显示表示出来,暂且称之为outer对象。外部类的引用在内部类的构造器中设置。下面的程序和上面的功能完全一样,最终在控制台输出100。

package com.xujin;

public class Test{
	public static void main(String...arg){
		OuterClass outerClass = new OuterClass();
		outerClass.setSecret(100);
		System.out.println(outerClass.getInfo());
	}	
}

class OuterClass{
	private int secret;
	
	public int getInfo(){
		Pair pair = this.new Pair(this);
		return pair.getSecret();
	}
	
	public void setSecret(int secret){
		this.secret = secret;
	}
	
	public class Pair{
		public Pair(OuterClass outerClass){
			OuterClass outer = outerClass;
			this.take = outer.secret;
		}
		
		public int getSecret(){
			return this.take;
		}
		
		private int take;
	}
}



局部内部类

在一个方法中定义的局部类,即局部内部类。它的作用与被限定在声明这个的块中。

局部内部类可以对外界完全的隐藏起来,除了定义局部类的方法,没有其他任何方法知道局部类的存在。

比如把上面程序中OuterClass的方法getInfo修改成下面这样:

public int getInfo(){
		class Pair{//修饰语 only abstract or final is permitted
			public Pair(){
				this.take = secret;
			}
			
			public int getSecret(){
				return this.take;
			}
			
			private int take;
		}
		Pair pair = new Pair();
		return pair.getSecret();
	}


匿名内部类

假如只创建了这个类的一个对象,就不必命名了。这种类被称为匿名类。

由于匿名内部类没有名字,而构造器的名字必须和类名一致,所以匿名内部类没有构造器。

匿名内部类是要扩展或实现父类或接口,所以只能是

  1. 继承一个类,重写方法
  2. 实现一个接口

下面的程序在外部类OuterClass中的getinfo方法中定义了一个实现了Pair接口的匿名内部类,并且调用其getSecret方法,返回一个int类型的值。

package com.xujin;

public class Test{
	public static void main(String...arg){
		OuterClass outerClass = new OuterClass();
		outerClass.setSecret(100);
		System.out.println(outerClass.getInfo());
	}	
}

class OuterClass{
	private int secret;
	
	public void setSecret(int secret){
		this.secret = secret;
	}
	
	public int getInfo(){
		return new Pair(){
			public int getSecret(){
				return secret;
			}			
			private int take;
		}.getSecret();
	}	
}

interface Pair{
	public int getSecret();
}


静态内部类

把一个类隐藏在另一个类的内部,内部类不可引用外部类对象,取消了产生的引用。

编译器会自动给内部类加上一个reference,指向产生它的那个外部类的对象,如果不想要或者说不需要这个reference,那么我们就可以把这个内部类声明为static,禁止这个reference的产生。

如下例子,OuterClass.StaticInnerClass直接就是一个类,别的类可以调用,而OuterClass.InnerClass根本不是一个可以用new OuterClass.InnerClass()初始化的类。

package com.xujin;

public class Test{
	public static void main(String...arg){
		OuterClass p = new OuterClass();
		p.fo();//com.xujin.OuterClass
		OuterClass.StaticInnerClass i = new OuterClass.StaticInnerClass(p);
		i.shuchu("world!");//Hello,world!
		i.getClassName();//com.xujin.OuterClass$InnerClass
		
		//OuterClass.InnerClass ic = new OuterClass.InnerClass();//error,这里OuterClass.InnerClass不是一个类型type,类比静态域和非静态域
		p.new InnerClass().getClassName();//com.xujin.OuterClass$InnerClass
	}	
}

class OuterClass{	
	static class StaticInnerClass{		
		StaticInnerClass(OuterClass outerClass){
			outer = outerClass;
		}
		
		public void shuchu(String name){
			
			System.out.println("Hello," + name);
		}
		
		public void getClassName(){
			System.out.println(this.getClass().getName());
		}
		
		private OuterClass outer;
	}	
	
	class InnerClass{
		public void getClassName(){
			System.out.println(this.getClass().getName());
		}
	}
	
	public void fo(){
		System.out.println(this.getClass().getName());
	}
	
	private int OuterPar;
}


下面这个例子单独把静态内部和非静态内部类的创建规则搞了个一通,方便以后查看。

package com.xujin;

//称Test类为其他类
public class Test{
	public static void main(String...arg){
		
		//在其他类中创建一个静态内部类
		//StaticInnerClass aStaticInnerClass = new StaticInnerClass();//必须加OuterClass
		OuterClass.StaticInnerClass aStaticInnerClass = new OuterClass.StaticInnerClass();
		//OuterClass.StaticInnerClass bStaticInnerClass = new OuterClass().new StaticInnerClass();//不能用外部类的实例创建静态内部类
		
		//在其他类中创建一个非静态内部类
		//OuterClass.InnerClass aInnerClass = new OuterClass.InnerClass();//错误,必须用一个外部类的实例new一个非静态内部类
		OuterClass.InnerClass aInnerClass = new OuterClass().new InnerClass();
		
		
	}	
	
	//其他类的静态函数和非静态函数创建内部类的方法一致
	public void amethod(){
		//在其他类中创建一个静态内部类
		OuterClass.StaticInnerClass aStaticInnerClass = new OuterClass.StaticInnerClass();
		
		//在其他类中创建一个非静态内部类
		//OuterClass.InnerClass aInnerClass = new OuterClass.InnerClass();//错误,必须用一个外部类的实例new一个非静态内部类
		OuterClass.InnerClass aInnerClass = new OuterClass().new InnerClass();		
	}
}

//称OuterClass类为外部类
class OuterClass{	
	static class StaticInnerClass{	
	}		
	class InnerClass{		
	}
	
	public void method(){
		StaticInnerClass aStaticInnerClass = new StaticInnerClass();
		//以下两个表明加不加OuterClass无所谓,对比其他类(其他类必须加OuterClass)
		OuterClass.StaticInnerClass bStaticInnerClass = new StaticInnerClass();
		StaticInnerClass cStaticInnerClass = new OuterClass.StaticInnerClass();
		
		InnerClass aInnerClass = new InnerClass();
	}
	
	public static void test(){
		StaticInnerClass aStaticInnerClass = new StaticInnerClass();
		//以下两个表明加不加OuterClass无所谓,对比其他类(其他类必须加OuterClass)
		OuterClass.StaticInnerClass bStaticInnerClass = new StaticInnerClass();
		StaticInnerClass cStaticInnerClass = new OuterClass.StaticInnerClass();
		
		//InnerClass aInnerClass = new InnerClass();//错误,在静态方法中不能直接创建非静态内部类,必须要有外部类的实例
		OuterClass.InnerClass aInnerClass = new OuterClass().new InnerClass();
	}
}


你可能感兴趣的:(java,java,java)