Java基础之—内部类

一、内部类

内部类是定义在另一个类中的类。

使用内部类的主要原因有以下几点:

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

内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。

内部类的对象总有一个隐式引用,它指向了创建它的外部类对象。这个引用在内部类的定义中是不可见的。外围类的引用在构造器中设置。编译器修改了所有的内部类的构造器,添加一个外围类引用的参数。当在外围类中创建内部类对象时,编译器就会将this引用传递给当前内部类构造器。

一个常规类A想要访问另一个类B的数据域,需要通过类B的公有方法。而将A设为内部类可以给予改进,即类B不必提供仅用于访问其他类的访问器。
内部类的这种访问特权使其与常规类比较起来功能更加强大。

注意:常规类的访问控制修饰符只有public(公有可见性)与default(即缺省,包可见性)。但内部类可以是private的,这时只有其外部类中的方法才能构造内部类对象。

1.2 内部类特殊语法规则

使用外围类引用的语法:

OuterClass.this表示外围类引用。如:

public void actionPerformed(ActionEvent event) {
	…
	if (TalkingClick.this.beep) Toolkit.getDefaultToolkit().beep();
}

outerObject.new InnerClass(construction parameters)用于更加明确地编写内部对象的构造器。如:

ActionListener listener = this.new TimePrinter();

当然,也可以通过显示地命名将外围类引用设置为其他的对象。如如果TimePrinterTalkingClock的公有内部类,可利用下述语句构造一个TimePrinter

TalkingClock jabberer = new Talking(10,true);
TalkingClock.TimePrinter listener = jabberer.new TimePrinter();

另外,在外围类的作用域之外,可以这样引用内部类:
OuterClass.InnerClass

注意
内部类中声明的所有静态域都必须是final。
内部类不能有static方法。Java语言规范对这个限制没有做任何解释。也可以允许有静态方法,但只能访问外围类的静态域和方法。

1.3 内部类是否有用、必要与安全性

内部类是一种编译器现象,与虚拟机无关。编译器将会把内部类翻译成$(美元符号)分隔外部类名与内部类名的常规类文件,而虚拟机对此一无所知。
如在TalkingClock类内部的TimePrinter类将被翻译成类文件TalkingClock.TimePrinter.class

通过反射可以查看,编译器为了引用外围类,在内部类中生成了附加的实例域this$0(名字由编译器合成,在自己编写的代码中不能引用它)。另外,在内部类的构造器中也自动添加了外围类参数。【详见"Java 核心技术卷I” P248】

内部类的访问特权的管理:
利用反射查看外部类,发现编译器在外围类中添加了静态方法,它将返回作为参数传递给它的对象域。【详见"Java 核心技术卷I” P249】

1.4 局部内部类

当一个内部类名字只在一个方法中创建该内部类对象时使用,可将该内部类定义在方法中,成为局部内部类。

public void start() {
	class TimePrinter implements ActionListener {
		public void actionPerformed (ActionEvent event) {
			System.out.println("At the tone, the time is " + new Date());
			if (beep) Toolkit.getDefaultToolkit().beep();
		}
	}
	
	ActionListener listener = new TimePrinter();
	Timer t = new Timer(interval,listener);
	t.start();
}

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

局部类优势:
1、局部类对外部世界可以完全隐藏起来,除该内部类声明所在的方法外,没有任何方法知道其存在。
2、局部类不仅能够访问包含它们的外部类,还可以访问局部变量。不过那些局部变量必须事实上为final。

1.5 匿名内部类

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

2、创建匿名内部类的通用语法格式为:

new SuperType (construction parameters) {
	inner class methods and data
}

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

例如:

public void start(int interval, boolean beep) {
	ActionListener listener = new ActionListenerr() {
		public void actionPerformed(ActionEvent event) {
			System.out.println("At the tone, the time is " + new Date());
			if (beep) Toolkit.getDefaultToolkit().beep();
		}
	};
	Timer t = new Timer(interval,listener);
	t.start();
}

【如果构造参数的闭小括号后面跟一个开大括号,正在定义的就是匿名内部类。】

3、由于匿名类没有类名,所以匿名类不能有构造器。取而代之的是,将构造器参数传递给超类(superclass)构造器。尤其是在内部类实现接口时,不能有任何构造参数。

4、Java程序员习惯性做法是用匿名内部类实现事件监听器和其他回调。如今最好还是使用Lambda表达式。

1.6 静态内部类

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

2、如果内部类对象是在外部类的静态方法中构造的,必须使用静态内部类。

3、注意
与常规内部类不同,静态内部类可以有静态域和方法。
声明在接口中的内部类自动成为static和public类。

以上参考:《Java核心技术 卷I》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值