Inner Class

内部类是一个非常重要的概念,了解内部类对lambda表达式的学习很有帮助

Java内部类

  1. 定义:Java内部类是定义在另一个类中的类

    • 内部类可以访问该类所在的作用域中的数据,包括私有数据。

    • 内部类可以对同一包中的其他类隐藏起来。

    • 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。

      使用内部类访问对象状态
      此处定义了一个TimerClock类。构造此类需提供interval,beep两参数

      public class TalkingClock
      {
         private int interval
         private boolean beep
      
         public TalkingClock(int interval, boolean beep){...}
         public void start(){...}
      
         public class TimePrinter implements ActionListener
          // an inner class
         {
             ...
         }
      }

      需要注意的是,这里TimePrinter类位于TalkingClock类内部,此处定义TimePrinter类。

      public class TimePrinter implements ActionListener{
         public void actionPerformed(ActionEvent event){
             System.out.print(new Date());
             if(beep) Toolkit.getDefaultToolkit().beep();
         }
      }

      可以看到神奇的事发生了,TimePrinter没有实例域或名为beep的变量,但却引用了TalkingClock的域。内部类既可以访问自身的域,也可以访问创建他的外围对象的域。

  2. 内部类的语法规则

    可以像这样编写在外部类中的内部类的构造器:

     outerObject.new InnerClass(Construction parameter)

    例如

       ActionListener listener = this.new TimerPrinter //多态声明

    this指代构造timePrinter对象的外围类。同时,也可在外部类外调用内部类。此处当timePrinter是一个公有内部类时,可以将外围类的引用设置为其他对象比如

       TalkingClock jabberer = new TalkingClock(1000,true);
       TalkingClock.TimerPrinter listener = jabberer.new TimerPrinter();
    
       TalkingClock.TimePrinter listener = new TalkingClock(1000,true).new TimerPrinter();//等价写法

    需要注意的是,内部类中所有声明的静态域都为final。内部类中不能有static方法。

  3. 局部内部类

    局部类通常被定义在方法中。

    public void start()
    {
        public void actionPerformed(Action event)
        {
            System.out.println(new Date());
            if(beep) Toolkit.getDefaultToolkit().beep();
        }
    
        ActionListener listener = new TimePrinter();
        Time t = new Timer(interval, listener);
        t.start();
    }

    局部类不能用public或public访问说明符进行声明,它的作用被限定在这个局部类的块中。局部类有一个优势,即对外部世界完全隐藏,即使外部类的其他代码也不能访问他,除start方法外,没有任何方法知道他的存在。

  4. 由外部类访问变量

    局部内部类若想访问所在方法的局部变量,该变量必须为有效final。原因有是因为,new出来的对象在堆内存中,局部变量由方法创建,在栈内存中,方法结束后自动清出。所以要使用final进行拷贝。

  5. 匿名内部类

    将局部内部类的使用在深入,假如只创建这个类的一个对象,就不必命名了。

     public void start(int interval, boolean beep){
         ActionListener listener = new ActionListener(){
             public void actionPerformed(ActionEvent event)
             {
                 System.out.println(new Date());
             }
         };
         Timer t = new TImer(interval,listener);
         t.start();
     }