内部类学习笔记
Java内部类:定义在另一个类中的类 成员内部类、静态内部类、局部内部类、匿名内部类
使用内部类的原因有三:
1.内部类方法可以访问该类所在作用域中的数据,包括私有的数据
2.内部类可以对同一个包中的其他类隐藏起来
3.当想要定义一个回调函数且不想编写大量的代码时,可以使用匿名内部类
使用内部类访问对象的状态:内部类的对象总有一个隐式引用,它指向了创建它的外部类对象。当然这个引用在内部的定义中是不可见的。
内部类中特俗的语法规则
内部类中有个外围的引用,事实上的引用表达式为:OuterClass.this 表示外围类引用
用Java核心技术中的例子
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class InnerClassTest
{
public static void main(String[] args)
{
TalkingClock clock = new TalkingClock(1000,true);
clock.start();
//keep program running until user selects "0k"
JOptionPane.showMessageDialog(null,"Quit program?");
System.exit(0);
}
}
/*
*A clock that prints the time in regular intervals.
*/
class TalkingClock{
private int interval;
private boolean beep;
public TalkingClock(int interval,boolean beep){
this.interval = interval;
this.beep = beep;
}
public void start(){
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval,listener);
t.start();
}
public 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();
}
}
}
在内部类中if 方法中的 变量 beep = TalkingClock.this.beep
那么定义内部类的构造器的方式可以是:outerObject.new InnerClass(construction parameters)
例子:ActionListener listener = this.new TimePrinter();
所以内部类的对象创建方式:
TalkingClock jabberer = new TalkingClock(1000,true); //外部类创建对象
TalkingClock.TimePrinter listener = jabberer.new TimePrinter();//内部类创建对象
需要注意,在外围类的作用域之外,可以这样引用内部类:
OuterClass.InnerClass
同时内部类中声明的所有的静态域都必须是final ,原因:我们希望一个静态域只有一个实例,创建的每一个外部类的对象,分别有一个单独的内部类实例,如果这个域不是final,它可能就不是唯一的
内部类不能有static方法,Java没有解释,但是可以理解与允许有static方法相比,坏处大于好处
简单的拓展一下关于内部类的安全性、有用性和必要性
当类TimePrinter被翻译成类文件TalkingClock$TimePrinter.class时,会生成了一个附加的实例域this$0(名字this$0是由编译器合成的,在自己编写的代码中不能够引用它)。另外,还可以看到构造器的TalkingClock参数,编译器在外围类添加静态方法access$0。它将返回作为参数传递给它的对象域beep,任何人都可以通过调用access$0方法很容易地读取到私有域beep
如果内部类访问了私有数据域,就有可能通过附加在外围类所在包中的其他类访问它们,但做这些事情需要高超的技巧和极大的决心。程序员不可能无意之中就获得对类的访问权限,而必须刻意地构建或修改类文件才有可能达到这个目的。
局部内部类
简单形容一下,把整个类比作是一个封闭的工厂,各种方法,参数、全局变量是工厂中封闭的工作间,那么工厂内部中,各种工作间能否相互协作,或者是工人能够自由的进入就是相当于各种方法中是否可以相互访问。
那么局部内部类,我的理解就是在工作间中创建一个小型的工厂,这个工厂比较特殊,因为这个工厂是放在工作间里面的,所以除了这个工作间的人,其他人都不知道这个工厂,也就是除了这个工作间,其他人都用不了
在局部内部类前不加修饰符public或private,其范围为定义它的代码块
注意:局部内部类中不可定义静态变量,可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的。
例子:
匿名内部类
匿名内部类可以使你的代码更加简洁,你可以在定义一个类的同时对其进行实例化。它与局部类很相似,不同的是它没有类名,如果某个局部类你只需要用一次,那么你就可以使用匿名内部类
例子
格式是:
new XXXX(){
方法体
};
应该是定义一个临时的类,所以要用;结尾
相当于我在创建一个对象
正常情况应该是 HelloWorld h1 = new HelloWorld();
匿名内部类的可以看作是,HelloWorld()这个类我没有,且我只需要调用这么一次,那么我特地定义一个HelloWorld的类会显得特别的麻烦,所以我就可以直接
HelloWorld h1 = new HelloWorld(){
方法体
};
可以看作创建一个临时的类
那么,这个时候匿名内部类就有平常创建对象的功能,可以继承父类,也可以实现接口等等
匿名内部类与局部类对作用域内的变量拥有相同的的访问权限。
(1)、匿名内部类可以访问外部内的所有成员;
(2)、匿名内部类不能访问外部类未加final修饰的变量(注意:JDK1.8即使没有用final修饰也可以访问);
(3)、属性屏蔽,与内嵌类相同,匿名内部类定义的类型(如变量)会屏蔽其作用域范围内的其他同名类型(变量):
(4)、匿名内部类中不能定义静态属性、方法;
(5)、匿名内部类可以有常量属性(final修饰的属性);
(6)、匿名内部内中可以定义属性,如上面代码中的代码:private int x = 1;
(7)、匿名内部内中可以可以有额外的方法(父接口、类中没有的方法);
(8)、匿名内部内中可以定义内部类;
(9)、匿名内部内中可以对其他类进行实例化。