《内部类》

内部类:(根据名字可得)定义在另一个类中的类。

使用内部类的原因:

1.内部类可以对同一个包中的其他类隐藏。

2.内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据。(寄生虫)

内部类之前对于简洁的实现回调十分重要,例如:

var one=new String[5];
one[0]=...one[1]=......;
Arrays.sort(one,new Comparator<String>(){public int compare(String a,String b){return a.length()-b.length();}});//one后面的都是匿名内部类。

不过lambda表达式取代了它回调的位置。不过内部类在其他方面仍有很大作用。

使用内部类访问对象状态:

下面提供一个实例来讲解内部类的访问。

构造一个语音时钟
public class TalkingClock
{
private int interval;//响一次的时间间隔
private boolean beep;//铃声是否开着

public TalkingClock(int interval,boolean beep){...}//普通构造器
public void start(){...}//通过该方法开始

public class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone,the time is"+Instant.ofEpochMilli(event.getWhen()));
if(beep)Toolkit.getDefaultToolkit().beep();//铃声具体内容。
}
}
注意:
1.TimePrinter类位于TalkingClock类内部,并不意味着每个TalkingClock都有个TimePrinter实例字段。
2.TimePrinter类没有定义beep变量,但方法进行了。

结论:

一个内部类可以访问自身的数据字段,也可以访问创建它的外围类的数据字段(包括私有变量,私有方法)。

原理:

内部类的对象总有一个隐式引用,指向创建它的外部类对象。

这个引用是不可见的,为了说明我们将它取名为outer。(具体叫啥不知道)。

那么outer=new TalkingClock(....)clock;beep(outer.beep);//outer指向外部类对象,beep实际为clock.beep;

外部类的引用在构造器中设置。编译器会修改所有的内部类构造器,添加一个对应外围类引用的参数。例如TimePrinter类的构造器:

public TimePrinter(TalkingClock clock)
{
outer=clock;
}

内部类的特殊语法规则:

我们解释了内部类有一个外围类的引用,叫作Outer。事实上,使用外围类引用的正规语法还要更复杂一些。表达式:OuterClass.this;(beep==TalkingClock.this.beep);

反过来,编写内部类对象的构造器:outerObject.new InnerClass();

例如:ActionListener listener=this.new TimePrinter();

注释:内部类中声明的所有静态字段都必须是final,并初始化为一个编译时常量。

局部内部类:定义在方法,代码块的内部类

直接代码实操:

public void start()
{
class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone,the time is"+Instant.ofEpochMilli(event.getWhen()));
if(beep)Toolkit.getDefaultToolkit().beep;
}
}
var listener =new TimePrinter();
var timer=new Timer(interval,listener);
timer.start();
}
//TimePrinter类定义在start方法中。

注意:

1.声明局部类不能有访问说明符(即public或private).

2.局部类的作用域被限定在声明这个局部类的块中。

3.局部类可以直接访问外部类的数据(包括私有)。

4.外部类通过方法来创建局部类(这个例子中用start方法)。

局部类有一个巨大优势即对外部世界完全隐蔽。除start方法外,没有任何方法知道TimePrinter类的存在。

由外部方法访问变量:

与其他内部类相比,局部类有一个优点。它不仅能够访问外部类的字段,还可以访问局部变量。不过这个变量必须是事实最终变量。(即赋值后绝不会改变)。上例子:

public void start(boolean beep)
{
class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if(beep){....}//TimePrinter没有定义beep却仍可以使用。
}
}
}

匿名内部类:

使用局部内部类时,可以只想创建这个类的一个对象,甚至不需要为类指定名字。(就是匿名内部类)。代码如下:

public void start(int interval,boolean beep)
{
var listener=new ActionListener()//局部类为:class TimerPrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println(.....)
}
};
var timer=new Timer(interval,listenre);
timer.start();
}

这个语法的含义是:创建一个类的新对象,这个类实现了ActionListener接口。

一般地,语法如下:

new SuperType(construction parameters)
{
inner class methods and data
}

其中,SuperType可以是接口,也可是类。如果是接口,内部类就要实现这个接口。如果是类,内部类就要扩展这个类。

由于构造器的名字必须与类名相同,而匿名内部类没有类名,所以匿名内部类没有构造器。实际上,构造参数要传递给超类构造器。具体地,只要内部类实现了一个接口,就不能有任何构造参数。不过仍然要提供一组小括号。

构造一个新对象与扩展那个类的匿名内部类的对象之间的差别:

var queen=new Person("Mary");//a Person object;
var count=new Person("Dracula"){...}
//an object of an inner class extending Person

如果构造参数列表的结束小括号后面跟一个开始大括号,就是在定义匿名内部类。

多年来,java程序员用匿名内部类实现事件监听器和其他回调。如今最好还是使用lambda表达式。

静态内部类:

有时候,使用内部类只是为了把一个类隐藏在另一个类的内部,并不需要内部类有外围类对象的引用。为此,可以将内部类声明为static,这样就不会生成哪个引用。

注释:只要内部类不需要访问外围类对象,就应该使用静态内部类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值