嵌套类和内部类

   可以在类的内部定义另外一个类,这种类就是所谓的嵌套类。嵌套类的作用域被限制在包含它的类之中。因此,如果类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()方法。
   正如以上所演示的,具有名称的和匿名的内部类使用一种简单并且高效的方式,解决了一些烦人的问题。它们还允许创建更高效的代码。

发布了59 篇原创文章 · 获赞 20 · 访问量 3651

猜你喜欢

转载自blog.csdn.net/qq_34896730/article/details/103534102
今日推荐