Java学习笔记---内部类

使用内部类的优点

内部类是定义在另一个类中的类,使用内部类主要有以下优点

①内部类方法可以访问该类的定义所在的作用域中的数据,包括私有的数据
②内部类可以对同一个包中的其他类隐藏其阿里
③使用匿名内部类比较便捷

使用内部类访问对象状态

package com.javatest;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

import javax.swing.JOptionPane;
import javax.swing.Timer;

public class TimerTest {
    public static void main(String[] agrs) {
        InnerClassTest t = new InnerClassTest(1000 );
        t.go();
        JOptionPane.showMessageDialog(null, "Quit program?");
        System.exit(0);
    }
}
class InnerClassTest {
private int interval;
    public InnerClassTest(int interval ) {
        this.interval = interval;
    }
    public void go() {
        Timer timer = new Timer(interval , new listeneraction());
        timer.start();
    }
    private class listeneraction implements ActionListener{
    @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("The time is " + new Date());
        }
}
}

listeneraction是一个内部类,这个类实现了接口ActionListener中的actionPerformed方法,然后类listeneraction作为实例传入Timer的构造器中,事实上,内部类listeneraction可以访问InnerClassTest 类的实例域,一个内部类可以访问自身的的数据域,也可以访问创建它的外围类对象的数据域
下面来看这是如何实现,在一个内部类中访问外部类的数据域,为了可以运行这个程序,内部类的对象总是有一个隐式引用,我们假设为Outer(Outer不是java的关键字)。
内部类对象拥有一对外部类对象的引用
这个引用在内部类的定义中是不可见的。

局部内部类

public void go() {
  class listeneraction implements ActionListener {
           @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("The time is " + new Date());
                if(beep){
                    Toolkit.getDefaultToolkit().beep();
                }
            }
        Timer timer = new Timer(interval , new listeneraction());
        timer.start();
        }

上面的例子就是一个局部内部类的例子,注意:局部类不能使用public或者private来修饰。它的作用域已经被限定在声明这个局部类的块中。除了,go方法外,没有任何方法知道listeneraction 的存在 。

局部内部类还有一个优点,它不仅可以访问包含它们的外部类,还可以访问局部变量 看下面的例子

public void go(int interval , boolean beep) {
        class listeneraction implements ActionListener {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("The time is " + new Date());
                if(beep){
                    Toolkit.getDefaultToolkit().beep();
                }
            }
        }
        Timer timer = new Timer(interval , new listeneraction());
        timer.start();
    }

将类InnerClassTest构造器的参数,interval,beep移动到go方法中。这看起来很正常,类listeneraction 访问beep变量似乎是合情合理的事情,我们思考一下整个的控制流程:调用go方法—>调用内部类listeneraction 的构造器—>将实例化的类对象listeneraction传入Timer构造器,调用stsrt方法,beep变量被释放—>最后,actionPerformed方法执行 if(beep)。从上面的流程中,要使actionPerformed方法可以正常工作,可以看出类listeneraction 在beep域被释放之前用go方法的局部变量进行了备份!
编译器必须检测对局部变量的访问,为每一个变量建立相应的数据域,并将局部变量拷贝到构造器中,以便将这些数据域初始化为局部变量的副本。局部类的方法只可以引用定义为final的局部变量,这样才使得局部变量与在局部类内创建的拷贝的变量保持一致

匿名内部类

假如只创建这个类的一个对象,就不用命名了,这就是匿名内部类。

public void go(int interval , boolean beep) {
        Timer timer = new Timer(interval, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("The time is " + new Date());
                if (beep) {
                    Toolkit.getDefaultToolkit().beep();
                }
            }
        }
        );
        timer.start();
    }

创建一个实现ActionListener接口的类的新对象,需要实现的方法actionPerformed定义在{}中。匿名类没有类名,所以不能有构造器。如今,使用匿名内部类还是使用Lambda表达式。

发布了40 篇原创文章 · 获赞 9 · 访问量 3285

猜你喜欢

转载自blog.csdn.net/weixin_44706647/article/details/102846937