可以在类的内部定义另外一个类,这种类就是所谓的嵌套类。嵌套类的作用域被限制在包含它的类之中。因此,如果类B是在类A中定义的,那么类B不能独立于类A而存在。嵌套类可以访问包含它的类的成员,包括私有成员。但是,包含类(包含嵌套类的类)不能访问嵌套类的成员。.嵌套类直接在包含类中作为成员声明。也可以在代码块中声明嵌套类。
嵌套类有两种类型:静态的和非静态的。静态的嵌套类是应用了static修饰符的嵌套类,因为是静态的,所以只能通过对象访问包含类的非静态成员。也就是说,嵌套类不能直接引用包含类的非静态成员。因为这条限制,所以很少使用静态的嵌套类。
嵌套类最重要的类型是内部类。内部类是非静态的嵌套类,可以访问外部类的所有变量和方法,并且可以直接引用它们,引用方式与外部类的其他非静态成员使用的方式相同。
下面的程序演示了如何定义和使用内部类。其中被命名为Outer的类有一个名为out_x的实例变量,一个名为test()的实例方法,并且还定义了一个名为Inner的内部类:
//Demonstrate an inner class.
class Outer {
int outer_x = 100;
void test(){
Inner inner = new Inner();
inner.display();
}
//this is an inner class
class Inner{
void display(){
System.out.println("display: outer_x = "+outer_x);
}
}
}
class InnerClassDemo {
public static void main(String[] args) {
Outer outer = new Outer();
outer.test();
/**
* 输出:
* display: outer_x = 100
*/
}
}
在此程序中,被命名为Inner的内部类是在Outer类的作用域内定义的。所以,Inner类中的所有代码,都可以直接访问变量outer_x。在Inner类中定义了一个名为display()的实例方法,该方法在标准输出流上显示outer_x。InnerClassDemo类中的main()方法创建了Outer类的一个实例,并调用这个实例的test()方法。该方法创建Inner类的一个实例,并调用display()方法。
只能在Outer类的作用域内创建Inner类的实例。如果试图在Outer类之外的任何代码中实例化Inner类,Java编译器就会生成错误。一般来说,必须通过封闭的作用域创建内部类的实例,如上面的实例所示。
内部类可以访问外部类的所有成员,但是反过来不可以。内部类的成员只有在内部类的作用域内才是已知的,并且外部类不能使用。例如:
//This program will not compile.
class Outer {
int outer_x = 100;
void test(){
Inner inner = new Inner();
inner.display();
}
//this is an inner class
class Inner{
int y = 10;// y is local to Inner
void display(){
System.out.println("display: outer_x = "+outer_x);
}
}
void showy(){
System.out.println(y);//error,y not know here!
}
}
在此,y被声明为Inner类的实例变量。因此,在Inner类的外部不知道y,并且showy()方法也不能使用它。
尽管我们一直主要关注的是,在外部类的作用域内作为成员声明的内部类,但是也可以在任何代码块的作用域内定义内部类。例如,可以在由方法定义的代码块中,甚至在for循环体内定义嵌套类,如下面这个程序所示:
//Define an inner class within a for loop.
class Outer {
int outer_x = 100;
void test(){
for(int i=0;i<3;i++){
class Inner{
void display(){
System.out.println("display: outer_x = "+outer_x);
}
}
Inner inner = new Inner();
inner.display();
}
}
}
class InnerClassDemo {
public static void main(String[] args) {
Outer outer = new Outer();
outer.test();
/**
* 输出:
*display: outer_x = 100
* display: outer_x = 100
* display: outer_x = 100
*/
}
}
尽管嵌套类并不是对于所有情况都适用,但是当处理事件时它们特别有用。
为了理解内部类提供的好处,考虑下面显示的applet。这个applet不使用内部类,目标是当按下鼠标时,在浏览器的状态栏中显示字符串“Mouse Pressed.”。在这个程序中有两个顶级类。MousePressedDemo类扩展了Applet类,MyMouseAdapter类扩展了MouseAdapter类。MousePressedDemo的init()方法用于实例化MyMouseAdapter,并作为addMouseListener()方法的参数以提供这个对象。
注意,指定applet的引用是作为MyMouseAdapter构造函数的参数提供的。这个引用存储在一个实例变量中,可方便以后mousePressed()方法使用。当按下鼠标时,通过保存的applet引用调用applet的showStatus()方法。换句话说,showStatus()方法。换句话说,showStatus()方法与MyMouseAdapter保存的applet引用有关。
import java.applet.Applet;
//This applet does NOT use an inner class.
public class MousePressedDemo extends Applet {
public void init(){
addMouseListener(new MyMouseAdapter(this));
}
}
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
class MyMouseAdapter extends MouseAdapter {
MousePressedDemo mousePressedDemo;
public MyMouseAdapter(MousePressedDemo mousePressedDemo){
this.mousePressedDemo = mousePressedDemo;
}
public void mousePressed(MouseEvent me){
mousePressedDemo.showStatus("Mouse Pressed.");
}
}
下面的程序显示了通过使用内部类可以如何改进前面的程序。在此,InnerClassDemo是顶级类,它扩展了Applet类。MyMouseAdapter 是内部类,它扩展了MouseAdapter 类。因为MyMouseAdapter 是在InnerClassDemo的作用域内定义的,所以可以访问InnerClassDemo作用域内的所有变量和方法。因此,mousePressed()方法可以直接调用showStatus()方法,而不用再需要通过保存指向applet的引用来调用。因此,不再需要向MyMouseAdapter()方法传递指向调用对象的引用。
import java.applet.Applet;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
//Inner class demo.
public class InnerClassDemo extends Applet {
public void init() {
addMouseListener(new MyMouseAdapter());
}
class MyMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent me) {
showStatus("Mouse Pressed.");
}
}
}
匿名内部类
匿名内部类是没有赋予名称的内部类。下面演示如何利用匿名内部类编写事件处理程序。
import java.applet.Applet;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
//Anonymous inner class demo
public class AnonymousInnerClassDemo extends Applet {
public void init(){
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me){
showStatus("Mouse Pressed.");
}
});
}
}
在这个程序中,有一个顶级类,名为AnonymousInnerClassDemo 。init()方法调用addMouseListener()方法。addMouseListener()方法的参数时用于定义并实例化内部类的表达式。
new MouseAdapter(){…}指示编译器,花括号中的代码定义了一个匿名内部类,并且该类扩展了MouseAdapter类,没有对这个新类进行命名,但是当执行这个表达式时会自动实例化这个新类。
这个匿名内部类因为是在AnonymousInnerClassDemo 类的作用域内定义的,能够访问AnonymousInnerClassDemo 类作用域内的所有变量和方法,所以可以直接调用showStatus()方法。
正如以上所演示的,具有名称的和匿名的内部类使用一种简单并且高效的方式,解决了一些烦人的问题。它们还允许创建更高效的代码。