java 内部类

来源:互联网 发布:wps数据透视表高级技巧 编辑:程序博客网 时间:2024/06/15 02:21

内部类(inner class)是定义在另一个类中的类。为什么要使用内部类呢?主要原因有以下三点:
1、内部类方法可以访问该类定义所在的作用于中的数据,包括私有的数据
2、内部类可以对同一个包中的其他类隐藏起来
3、当想要定义一个回调函数且不想编写大量代码时,使用匿名(annoymous)内部类比较便捷
我们将这个比较复杂的内容分几部分介绍
1、给出一个简单的内部类,他将访问外围类的实例域
2、给出内部类的特殊语法规则
3、领略一下内部类的内部,探讨一下如何将其转换为常规类
4、讨论局部内部类,他可以访问外围作用域中的局部变量
5、介绍匿名内部类,说明在java有lambda表达式之前用于实现回调的基本方法
6、介绍如何将静态内部类嵌套在辅助类中
嵌套是一种类之间的关系,二是不是对象之间的关系。一个LinkedList对象并不包含Iterator类型或者Link类型的子对象。
嵌套类有两个好处:命名控制和访问控制。由于名字Iterator嵌套在LinkedList类的内部,所以在外部命名为LinkedList::Iterator,这样就不会与其他名为Iterator的类发生冲突。在java中这个并不重要,因为java包已经提供了相同的命名控制。需要注意的是,Link类位于LinkedList类的私有部分,因此,Link对其他的代码均不可见。鉴于此种情况,可以将Link的数据与设计为公有的,他仍然是安全的。这些数据域只能被LinkedList类中的方法访问,而不会暴露给其他的代码。在java中,只有内部类可以实现这样的控制。
然而,java内部类还有另外一个功能, 这使得它比C++的嵌套类更加丰富,用途更加广泛。内部类的对象有一个隐式调用,他引用了实例化该内部对象的外围类对象。通过这个指针,可以访问外围类对象的全部状态。
在java中,static内部类没有这种附加指针,这样的内部类与C++中的嵌套类很相似。

使用内部类访问对象状态

内部类的语法比较复杂。鉴于此情况,我们选择一个简单但不太实用的例子说明内部类的使用方式
下面将进一步分析TimerTest示例,并抽象出一个TalkingClock类,构造一个语音时钟需要提供两个参数:发布通告的事件和开关铃声的标志。

package3章;import java.awt.*;import java.awt.event.*;import java.util.*;import javax.swing.*;import javax.swing.Timer;/** * * @author cmx */public class Timer_test{    public static void main (String[] args)    {        Outer clock=new Outer(1000,true);        clock.Beep();    }}class Outer{    private int interval;    private boolean beep;    public Outer(int interval ,boolean beep)    {        this.interval=interval;        this.beep=beep;    }    public void Beep()    {        ActionListener ok=new well();        Timer t=new Timer(interval,ok);        t.start();    }    /**     * 以下为内部类 InnerClass     */    public class well implements ActionListener    {        public void actionPerformed(ActionEvent e)        {            System.out.println("this is the "+new Date());            if(beep)                Toolkit.getDefaultToolkit().beep();        }    }}

内部类的特殊语法规则
我们已经讲述了内部类有一个外围类的引用outer。事实上,使用外围类引用的正规语法还要复杂一些。表达式

OuterClass.this

表示外围类引用。例如,可以像下面这样编写TimerPrinter内部类的actionPerformed方法
原方法:

public class well implements ActionListener    {        public void actionPerformed(ActionEvent e)        {            System.out.println("this is the "+new Date());            if(beep)                Toolkit.getDefaultToolkit().beep();        }    }

完整语法:

public void actionPerformed(ActionEvent event){    ...    if(Outer.this.beep)        Toolkit.getDefaultToolkit().beep();}

代替:

if(beep)                Toolkit.getDefaultToolkit().beep();

反过来,可以采用下列语法格式更加明确的编写内部类对象的构造器
原默认构造器:

//调用函数中,外部类的引用为:Outer  O=new Outer(...);public well(Outer c){    O=c;     //?}
//新内部对象构造器:public well(Outer c){     O.new well(construction parameter)  //?}

例如:
ActionListener ok=this.new well();
在这里,最新构造的well对象的外围类引用被设置为创建内部类对象的方法中的this引用。这是一最常见的情况。通常,this限定词是多余的。不过,可以通过显式的命名将外围类引用设置为其他的对象。例如:如果well是一个公有的内部类,对于任意的语音时钟都可以构造一个well:

//原引用方式:public class Timer_test{    public static void main (String[] args)    {        Outer clock=new Outer(1000,true);        clock.Beep();    }}+class Outer{    private int interval;    private boolean beep;    public Outer(int interval ,boolean beep)    {        this.interval=interval;        this.beep=beep;    }    public void Beep()    {        ActionListener ok=new well();        // ActionListener ok=this.new well();        Timer t=new Timer(interval,ok);        t.start();    }

新的引用方式

Outer j=new Outer(1000,true);  //外围类引用(总调用)Outer.well a=j.new well();

也就是:

public class Timer_test{    public static void main (String[] args)    {        Outer clock=new Outer(1000,true);        clock.Beep();        /*        Outer j=new Outer(1000,true);  //外围类引用(总调用)        Outer.well a=j.new well();        */    }}

需要注意:在外围类的作用域外,可以这样引用内部类:

OuterClass.InnerClass例如:Outer.wellOuter j=new Outer(1000,true);  //外围类引用(总调用)        Outer.well a=j.new well();

注意:内部类中声明的所有静态域都必须是final。原因很简单。我们希望一个静态域只有一个实例,不过对于每一个外部对象,会分别有一个单独的内部类实例。如果这个域不是final,他可能就不是唯一的。
如果不是final就出出现:

  Cannot refer to a non-final variable mylis inside an inner class defined in a different method

内部类不能有

阅读全文
0 0
原创粉丝点击