Java中的匿名内部类:由setOnClickListener说起

在初学Android的时候,总是看到这样一段代码:

Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, 'onClick', Toast.LENGTH_SHORT).show(); } });

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

相信大家对上面这段代码都不陌生,确切的说是再熟悉不过了,咱从学习Android的第一天起就已经开始写这种代码了。没错,确实我们在初学Android的时候就已经开始使用匿名内部类了,但是随着使用的深入,会发现越来越多的问题,例如,为什么这个类里面可以随意使用MainActivity(外部类)里面的所有成员变量,即使是private的变量?为什么当需要一个context的时候却要写MainActivity.this这样的形式?为什么在申明这个内部类的方法里定义的局部变量需要定义为final才能在内部类里面使用?别急,在下为大家逐个解释。
要解释这些问题,首先需要从java的内部类说起(本文不打算详细介绍这个语法,想要详细了解的同学可以求助度娘)
java中的内部类一言以蔽之就是,申明在一个类或者方法里面的类(new onClickListener()就是申明在一个类里面的内部类,同时还是匿名的),最典型的内部类申明如下:

class Outer {    private String name = 'Outer';
    class Inner {        public void print() {
            System.out.println('Class Name is: ' + name);
        }
    }
}1234567812345678

上述代码中,类Inner申明在类Outer内部,我们称Inner为Outer的内部类,使用内部类好处多多,例如内部类可以直接使用外部类中的所有成员变量和方法,便于代码管理维护,内部类可以用于隐藏实现细节,可以用于实现类的多重继承…(多了就不写了,当时我在学习的时候看到这么多内部类的使用方法感觉云里雾里,直到后来代码见多了才逐渐理解,所以建议大家刚开始不要想着把所有知识点全部搞清楚,先在自己脑中有点印象,以后在编码或读源码的过程中遇到后再逐步去理解,这样跟着实例去理解不仅具体,而且深刻)。
现在大家清楚了吧,为什么onClickListener这个类里面可以使用MainActivity这个类中的所有成员变量和方法,等等,刚刚不是说可以使用所有成员变量么,那为什么会有MainActivity.this这种奇葩的写法。好吧,刚刚没说清楚,大家有没有想过如果内部类中有同名的变量或者方法的时候怎么处理,很简单就是加上外部类的类名+.然后再写上变量名,例如刚刚那个例子,如果内部类中也有一个同名的变量name,则可以这么写:

class Outer { private String name = 'Outer'; class Inner { private String name = 'Inner'; public void print() { System.out.println('InnerClass Name is: ' + name); System.out.println('OuterClass Name is: ' + Outer.name); } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

这也就解释了为什么要写成MainActivity.this这种形式了,因为内部类onClickListener这个类里面已经有一个同名变量this了,如果想要使用外部类MainActivity的this变量,则需要使用MainActivity.this。
好了,内部类的知识先讲到这里(更多详细用法如果大家真的等不及可以自行百度,不过我真的建议大家在使用过程中逐步去发现内部类的使用实例,自己去理解它的用法),下面再说说匿名内部类。
如果一个内部类在并不是显式得使用class关键字来申明,即没有给该内部类一个名字,我们把这种类叫做匿名的内部类,匿名内部类可以用来实例化一个类或者接口,最常见的匿名内部类当属多线程中的Runnable接口:

final int count = 100;        new Thread(new Runnable() {            @Override
            public void run() {                for(int i = 0; i < count; i++) {
                    System.out.println('current num is:' + i);
                }
            }
        }).start();123456789123456789

相信大家对上面这段代码都不会陌生,简直是太熟悉了啊,基本在使用多线程的时候就能见到(当然不排除你是继承Thread类来做的,那我就没办法了)。这里面的Thread以及Runnable其实都是一种匿名内部类。细心的朋友会注意到,这里count被申明为了final,这是怎么回事,我不申明为final难道不行吗,成,行不行咱先试试,把final去掉,我去,编译器怎么报错了!可以看到,编译器不允许在匿名内部类中使用非final类型的变量,这是什么原因呢?大家有没有想过,在申明内部类的时候,例如上述代码,在执行start之后,该局部方法就返回了,那么作为局部变量的count生命周期结束后会被回收,这个时候thread里面的for循环还在执行,此时再引用局部变量count就会变得很奇怪了吧,明明都回收了还怎么使用。好吧,在java中,编译器是这样处理内部类的:如果这个外部局部变量是常量,则在内部类代码中直接用这个常量。如果是类的实例,则编译器将产生一个内部类的构造参数,将这个final变量传到内部类里,这样即使外部局部变量无效了,还可以使用。
好了,那么关于匿名内部类,就先说到这里,我们在编写代码的时候不光要做到知其然,还要做到知其所以然,希望这篇文章能对大家有所帮助。

(0)

相关推荐

  • Java中的匿名内部类

    一.匿名内部类 之前的所有类都有自己的名字,但是有时候如果某个接口的实现类(或者某个父类的子类)只需要使用一次,此时这样的类如果我们单独定义出来则需要单独为其创建一个"*.java" ...

  • Java 中的关键字

    Java 中有多少个关键字,有大小写之分吗? Java 中有 48 个关键字在使用 + 两个保留关键字未使用,共 50 个关键字. Java 关键字全部都由是小写组成. Java 中保留关键字分别是哪 ...

  • Java中的方法内部类

    一:方法内部类 就是在方法中直接定义一个内部类,之后直接使用这个内部类对象的方法,你作为语法 了解就行了. DEMO:方法中定义内部类     以上是在方法中定义了一个内部类,方法中的内部类能访问方法 ...

  • Java | 在 Java 中执行动态表达式语句: 前中后缀、Ognl、SpEL、Groovy、Jexl3

    在一些规则集或者工作流项目中,经常会遇到动态解析表达式并执行得出结果的功能. 规则引擎是一种嵌入在应用程序中的组件,它可以将业务规则从业务代码中剥离出来,使用预先定义好的语义规范来实现这些剥离出来的业 ...

  • Java中String类的concat方法

    在了解concat()之前,首先需要明确的是String的两点特殊性. 长度不可变 值不可变  这两点从源码中对String的声明可以体现: private final char[] value ; ...

  • java中堆栈(stack)和堆(heap)

    (1)内存分配的策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编 译时就可以给 ...

  • Java中的通配符

    一.通配符概念 其实.上很多技术点都是为了解决某一问题而出现的,那么我们在学习的过程中可以先提出问题,然后在使用我们的技术去解决. DEMO:观察问题 以上代码可以正常执行,但是如果泛型类中的类型改变 ...

  • Java中zip的压缩和解压缩

    在Java中可以使用ZipOutputStream和ZipInputStream来实现zip的压缩和解压缩操作,另外使用FileSystem也可以用来实现zip的解压缩,下面将介绍这几种方式,直接上代 ...

  • 高级开发必须理解的Java中SPI机制

    本文通过探析JDK提供的,在开源项目中比较常用的Java SPI机制,希望给大家在实际开发实践.学习开源项目提供参考. 1 SPI是什么 SPI全称Service Provider Interface ...