`
DBear
  • 浏览: 231231 次
  • 性别: Icon_minigender_2
  • 来自: 上海
社区版块
存档分类

Inner Classes小结

阅读更多

   Inner Classes 在平常的应用中虽然不是很多,但是仍然有很多细节问题值得注意,需要掌握。因此,这里对这方面内容做一小结。

   Inner Classes,顾名思义,就是定义在另一个类中的类,之所以出现这一概念,主要是因为它具有如下两个特点:  

  1. inner classes中的方法可以访问类定义域内的所有数据, 哪怕数据是private的。
  2. inner classes对同包内的其它类是不可见的。

   常规内部类

   下面,我将针对一段具体代码,对Inner Classes的特性和应用作具体的阐述。

public class TimerTestForInnerClass {
    public static void main(String[] args) {
        TalkingClock clock = new TalkingClock(100, true);
        clock.start();
	
        JOptionPane.showMessageDialog(null, "Quit Program?");
        System.exit(0);
    }
}

class TalkingClock {
  private int interval;
  private boolean beep;
  
  public TalkingClock(int interval, boolean beep) {
      this.interval = interval;
      this.beep = beep;
  }
  
  public void start() {
      ActionListener listener = new TimePrinter();
      Timer t = new Timer(interval, listener);
      t.start();
  }
  
  public class TimePrinter implements ActionListener {
      public void actionPerformed(ActionEvent event) {
          Date now = new Date();
          System.out.println("At the tone, the time is " + now);
          if (beep) Toolkit.getDefaultToolkit().beep();
      }
  }
  
}

 

    在上面的代码中,TimePrinter是TalkingClock的内部类。仔细观察,发现actionPerformed方法中引用的beep变量在TimePrinter中并没有定义,它是外部类TalkingClock的成员变量。这就是inner classes特点一的展示,之所以可以如此,是因为inner class在被创建时获得了外部类的一个引用,这个引用是由编译器自动传给内部类的构造函数的,因此,内部类中使用的beep变量的完整形式其实是:

 

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

   上述代码中的OuterClass.this代表的就是外部类的引用。

   如果内部类是public的,那么我们也可以在外部类以外来创建内部类,方法如下:

TalkingClock jabberer = new TalkingClock(1000, true);
TalkingClock.TimePrinter listener = jabberer.new TimePrinter();

  

Local Inner Classes 局部内部类

   内部类除了可以作为外部类的成员,还可以定义在外部类的方法中,这样的内部类称为:Local Inner Classes。Local Inner Classes不需要访问权限修饰符(access specifier),因为它们的作用域受它们被定义的块域的限制。Local Inner Classes的一个重要的优点是,除了定义它们的方法以外,外界任何类或方法都无法访问它们。因此,当一个内部类只需要被一个方法使用,并且想屏蔽任何其他方法时,就可以将它们定义为Local的。

public void start() {
    class TimePrinter implements ActionListener {
      public void actionPerformed(ActionEvent event) {
          Date now = new Date();
          System.out.println("At the tone, the time is " + now);
          if (beep) Toolkit.getDefaultToolkit().beep();
      }
    }
    ActionListener listener = new TimePrinter();
    Timer t = new Timer(interval, listener);
    t.start();
}

   上面的代码就是Local Inner Class的应用实例。

   

    Local Inner Class不光可以使用Outer Class的成员变量,还可使用它所在方法的参数以及方法中的局部变量。但要注意一点,这些外部引用变量都必须是final型,否则会收到编译器错误。见下面的代码:

public void start(int interval, final boolean beep) {
    class TimePrinter implements ActionListener {
      public void actionPerformed(ActionEvent event) {
          Date now = new Date();
          System.out.println("At the tone, the time is " + now);
          if (beep) Toolkit.getDefaultToolkit().beep();
      }
    }
    ActionListener listener = new TimePrinter();
    Timer t = new Timer(interval, listener);
    t.start();
}

   我们来简单了解下beep参数是如何传入内部类的方法中。直观来看,beep变量是无法存留到actionPerformed方法执行之时的,它在start()方法执行结束之后就被回收了,而actionPerformed则要过短时间才执行,因此,为了正常使用beep变量,我们需要为它做一个copy,并将这个copy传进内部类中。所以,内部类中所谓的beep,其实是原有变量的副本。

 

TIP:为什么只有final型的参数或局部变量可以传入inner class?(整理自Core Java,如有不妥,敬请指正)

在很多时候,这个final的限制其实为我们带来了很多不便,因为我们有的时候确实是想要在inner class中改变局部变量的,如下面这段代码:

int counter = 0;
Date[] dates = new Date[100];
for (int i = 0; i < dates.length; i++)
   dates[i] = new Date() {
          public int compareTo(Date other) {
              counter++; // ERROR

              return super.compareTo(other);
          }
   };

Arrays.sort(dates);
System.out.println(counter + " comparisons.");

 

   我们只是想获取比较次数,但是由于内部类的final限制,这样的代码显然是不合法的。但如果直接加上final,我们的update目标又无法达到,所以,只能做如下的转换:

final int[] counter = new int[1];
for (int i = 0; i < dates.length; i++)
   dates[i] = new Date() {
          public int compareTo(Date other) {
              counter[0]++;
              return super.compareTo(other);
          }
   };

    这样,虽然counter是final的,但是我们却可以随意改变它内部的值,从而变相的达到了update的目标。

    事实上,在inner class起初创建时,这种从primitive型到array型的转换最开始是由编译器自动完成的,但是开发者们很害怕编译器在“背着他们”创建那么些对象,因此,最后还是决定加上final这个限制,如果需要在inner class中改变变量值,那就让programer自己去做转换。而且,也并不排除,随着Java语言的不断完善,会有更好的方式来替代final限制,达到原有的安全效果。

  

分享到:
评论

相关推荐

    Android开发导入项目报错Ignoring InnerClasses attribute for an anonymous inner class的解决办法

    在Android开发过程中,有时会遇到导入项目时出现错误警告,比如"Ignoring InnerClasses attribute for an anonymous inner class"。这个问题并不会阻止项目在Windows系统上运行,但可能会导致在其他平台如OS X上无法...

    静态内部类(Static Inner Classes)1---马克-to-win java视频

    静态内部类 Static Inner 马克-to-win java视频的详细介绍

    【SQL】在sql server中 delete时 使用INNER JOIN

    ### SQL Server 中 DELETE 语句结合 INNER JOIN 的应用 #### 背景介绍 在数据库管理与维护过程中,经常会遇到需要删除表中的某些记录的情况。简单地使用 `DELETE` 语句可以删除单个表中的数据,但在多表关联的情况...

    sql的 INNER JOIN 语法

    3. **连接顺序**:连接表的顺序可能会影响查询性能,通常先连接较小的表可以提高执行速度。 4. **多表连接**:当涉及到多个表的连接时,合理的连接顺序和分组方式对于优化查询至关重要。 #### 五、总结 通过以上...

    SQLInner防止SQL注入式攻击源码

    SQLInner是一种专门用于防止SQL注入的工具或库,它的目标是确保应用程序的SQL查询不会被恶意输入所利用。在这个源码中,我们可以深入学习如何在编程中实现这样的防御机制。 SQL注入的常见方式包括通过HTTP请求传递...

    Static修饰内部类

    彦舜原创,CSDN首发:希望对你有所帮助,仅此而已。内容工整规范,是作者本人,逐句敲出来,同时也含有个人的一些独见。

    java实现innerjoin关联算法

    ​ 场景:有三个List变量,分别为list1、list2、list3 List,Object&gt;&gt; list1 = new ...在sql中就是"select * from list1 inner join list2 on list1.column1=list2.column2 inner join list3 on list1.column3=list

    MySQL中视图的使用及多表INNER JOIN的技巧分享

    INNER JOIN table2 t2 ON t1.fid = t2.fid) INNER JOIN table3 t3 ON t1.mid = t3.mid; 这里使用了3表关联,对于多表关联的 INNER JOIN 写法有一个技巧 1. 先写最简单的2表关联 INNER JOIN 2. 然后使用 () 从 FROM ...

    inner join、 left join 、right join、 outer join之间的区别

    ### inner join、left join、right join、outer join之间的区别 在数据库操作中,连接(Join)是一种非常重要的操作,用于组合两个或多个表中的数据。根据连接的方式不同,可以分为几种类型:`INNER JOIN`、`LEFT ...

    Inner-IoU: More Effective Intersection over UnionLoss with Auxil

    对于高IoU样本,使用较小的辅助边界框计算损失可以加速收敛,而较大的辅助边界框适合于低IoU样本。然后,我们提出了Inner-IoU损失,通过辅助边界框计算IoU损失。对于不同的数据集和检测器,我们引入一个缩放因子比来...

    SQL 外链接操作小结 inner join left join right join

    SQL 外链接操作小结 inner join left join right join SQL 外链接操作是关系型数据库管理系统中的一种基本操作,用于从多个表中检索数据。外链接操作可以分为三种:inner join、left join 和 right join。 inner ...

    Inner-Classes:内部阶级的概念

    内部类(Inner Classes)是Java编程语言中的一个特色特性,它允许我们在一个类的内部定义另一个类。这种设计模式在处理一些特定问题时非常有用,比如实现事件监听、封装复杂逻辑或者创建私有辅助类。内部类有四种...

    Binner轮播图(Java)

    此资源是Binner轮播图,可应用于广告位,类似于淘宝主页轮播。此资源用java写的,我还有kotlin版本在我的下载资源中。

    inner join的使用例子【之一】

    利用inner join 查找出ERP系统中某销售订单所关联的生产任务单、入库单、领料单等单据情况。

    java_innerclass_instance.rar_innerclass

    Java 内部类(Inner Class)是 Java 语言的一个特性,它允许我们在一个类的内部定义另一个类。这种设计模式提供了更高的代码封装性和复用性,同时也为解决某些特定问题提供了方便。在“java_innerclass_instance.rar...

    java-内部类(InnerClass)详解.pdf

    内部类分为几种类型,包括静态成员类(Static member class)、局部内部类(Local inner class)、匿名内部类(Anonymous inner class)以及嵌套接口(Nested interface)。在本讨论中,我们将主要聚焦于静态成员类...

    关于SQL 中的inner join的使用

    ### SQL中的INNER JOIN详解 #### 一、INNER JOIN的基本概念 **INNER JOIN** 是SQL中最常用的连接类型之一,主要用于从两个或多个表中提取数据,其中仅返回那些满足连接条件的记录。简单来说,INNER JOIN返回的是两...

    Java中inner_class内部类

    Java中的内部类(Inner Class)是Java语言特性中一个独特且强大的工具,它允许在一个类的内部定义另一个类。这种设计模式提供了许多便利,包括封装、代码复用、以及对匿名类的支持。本文将深入探讨Java内部类的概念...

    Binner轮播图(Kotlin)

    **Binner轮播图**是一种常见的用户界面组件,尤其在电商、新闻和其他需要展示一系列可滑动内容的应用中。在Android开发中,实现这样的功能通常需要利用到自定义视图或者第三方库。在这个资源中,开发者提供了一个用...

Global site tag (gtag.js) - Google Analytics