专栏首页中国Android研究院你说你是高工,匿名内部类有我玩得6吗?

你说你是高工,匿名内部类有我玩得6吗?

阅读文本大概需要 5 分钟。

1

基础知识

匿名内部类大家肯定都很熟悉,如果你是做Android开发的一定再熟悉不过了,因为你学Android的时候写的第二行代码一定是setOnClickListener,第一行代码一般是findViewById。

写个简单的匿名内部类:

public abstract class Test {
    abstract void onClick();
}
    
Test test = new Test() {
    @Override
    void onClick() {  
    }
};

作为一个初级工程师,一般能使用就ok了。

匿名内部类,顾名思义就是不知道名字的内部类。它真的就没有名字吗?有想过这个问题吗?如果你想过,那证明你是一个不甘于做初级工程师,想往上拔高的人。事实上匿名内部类在被编译成字节码的时候会被定义一个类名,只是类名呢不是那么的被人类所容易阅读,假设上面那个匿名内部类的外部类为OuterClass,编译器编译后就会将上面的匿名内部类定义为:"包名.OuterClass$1",其中里面的'$1'指的是OutterClass类里面的第一个匿名内部类。如果你怀疑它的正确性,可以验证下:

Class testClass = Class.forName("包名.OuterClass$1");
System.out.println(testClass);

2

继承结构

以上面举的例子来说,匿名内部类的父类是Test,或者我们常用的setOnclickListener(new OnclickListener{})来说,就是实现OnClickListener接口的匿名内部类。

那么我们能不能同时继承一个类和实现一个接口呢?像这样:

Test|OnClickListener testListener = new Test() implements OnClickListener{
    ...
}

这种可以吗?在有些语言是支持的,但是呢Java是不支持的。我们知道Java10支持类型推导了,那上面的例子可不可以写成这样呢?

var testListener = new Test() implements OnClickListener{
    ...
}

可不可以呢?其实也是不可以的,那有同学就讲了,你在这瞎折腾了半天,都是不可以那还讲干啥?聪明的同学可能能从上面也能吸取到一些知识。比如,你可以去查一下哪些语言支持第一种方式,这里只是给你抛砖引玉用的。从第二种方式中我讲到了Java 10支持了类型推导,那你也可以再去查下Java 10到底新增了哪些新特性是不是?那到底能不能实现呢?当然是可以的,你可以使用Java的local class。感兴趣的读者自行查阅一下哦。

如果你是中级工程师掌握到这里就蛮不错的了。

3

构造方法

匿名内部的构造方法是谁定义的?很显然开发者并没有机会去定义,是由编译器给我们编译的,在非静态区里面,我们写匿名内部类时会持有外部类的引用,那这个引用编译器会帮我们作为构造方法的参数传进去。举个例子:

由于我们的内部类是非静态的所以是需要持有内部类InnerClass的外部类的实例(OuterClass的实例),而我们的匿名内部类也是在非静态的方法区中,那么就会持有匿名内部类$1的外部类的实例(Client的实例),所以编译器给我们的匿名内部类定义的构造方法中带上了两个实例的参数。

那如果我们将内部类换成Interface呢?Interface跟静态内部类的效果一样,就不会引用外部类的实例,所以这时候编译器在定义匿名内部类的构造方法时只会将匿名内部类的外部类实例带入,而不会将内部类的外部类实例带入:

如果我们将匿名内部类放在静态的方法中,那么编译器就不会将任何外部类的实例作为构造方法的参数传入了。

还有一个我们在匿名内部类访问局部变量时,需要将局部变量声明为final的。原因是什么呢?因为如果你在匿名内部类访问局部变量的时候,编译器一样会在匿名内部类的构造方法中将其作为参数传进去,不过呢,传进去的时候是当时的一个拷贝,如果不是final的,那么你的代码在后面对变量进行更改的话,那么在匿名内部类中使用的还是旧的值,这样处理显然会有问题,所以Java要求必须使用final来声明。如图:

所以,综上我们知道匿名内部类的构造方法的定义是:

  • 由编译器定义
  • 构造方法的参数
    • 外部类的对象(定义在非静态方法区)
    • 父类的外部类的对象(父类是非静态的)
    • 父类的构造方法参数
    • 外部捕获的变量(方法体引用的局部final变量)

到这里为止,如果你都知道的话,我觉你已经有了高工的思维高度了。

本文分享自微信公众号 - IT烂笔头(nj_android),作者:手艺人

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 千万别告诉别人,这是我从高工那偷听来的Java方法分派策略

    我们知道Java有一大特性就是多态。讲到多态不得不想再深层次的研究下多态中的方法分派到底是采用什么样的策略的。

    吴延宝
  • Http知道这些,开发Android才算合格!

    说起HTTP大家再熟悉不过了,无论是大学的课本上还是平时的工作中,几乎每天都要和HTTP打交道。但是,就是这么熟悉的老朋友,你真的是非常了解吗?你能轻而易举就回...

    吴延宝
  • 【图鉴】AI时代,你是不是那个背锅侠?

    大厂出品、GitHub上千Star、大神操刀等都是开源项目的质量保证,但是漏洞、翻车、崩溃的事件也屡见不鲜~~~

    吴延宝
  • LightOJ - 1214 Large Division 大数取余

    用户2965768
  • Thrift前端上手实例

    这个项目用来帮助那些对thrift感兴趣的前端们上手thrift, 你可以把它认为是一个简易的使用案例或是指南, 毕竟thrift的官方文档真的很简单...

    IMWeb前端团队
  • Thrift前端上手实例

    ? 项目介绍 项目地址 这个项目用来帮助那些对thrift感兴趣的前端们上手thrift, 你可以把它认为是一个简易的使用案例或是指南, 毕竟thrift的...

    IMWeb前端团队
  • 一个简单案例,5 分钟看懂 Java Lamdba 表达式

    JDK8引入了一个新玩意,叫做lamdba(那么大)的表达式,说得神乎其神,说真的,这玩意吧,并不难,但是要讲清楚吧,也不是太容易的事情。

    芋道源码
  • 百度助力数据挖掘世界杯KDD Cup 历史性革新

    8月6日,一年一度的KDD(国际数据挖掘与知识发现)大会召开,这是数据挖掘领域国际最高级别会议,而其旗下赛事KDD Cup 被称为数据挖掘领域的“世界杯”。今年...

    用户1386409
  • BigBiGAN问世,“GAN父”都说酷的无监督表示学习模型有多优秀?

    众所周知,对抗训练生成模型(GAN)在图像生成领域获得了不凡的效果。尽管基于GAN的无监督学习方法取得了初步成果,但很快被自监督学习方法所取代。

    AI科技大本营
  • 浅谈用户行为分析之用户身份识别:cookie 知多少?

    对于数据统计分析或者数据挖掘而言,用户是个非常重要的维度,也是统计分析能落地的基础。一般而言,咱们追踪或者识别一个用户的首选方案是 userID,大多数公司的产...

    用户1177713

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动