https://blog.csdn.net/z69183787/article/details/68490440

https://www.zhihu.com/question/21395848

https://www.zhihu.com/question/24084277/answer/110176733

喜欢看生肉的同学就不用看我的回答了,直接看R大的三篇回答,尤其是第一篇后面的回复部分。

我只是试着用大白话做个简单的整理,希望能更容易理解一点。

关于对象与闭包的关系的一个有趣小故事
(这篇的精华在后面的回复,小故事可以跳过)

JVM的规范中允许编程语言语义中创建闭包(closure)吗?
- RednaxelaFX 的回答

为什么Java闭包不能通过返回值之外的方式向外传递值?
- RednaxelaFX 的回答

1.
闭包(Closure)
什么是闭包,大白话不怎么严谨的说就是:

  1. 一个依赖于外部环境自由变量的函数
  2. 这个函数能够访问外部环境里的自由变量

看下面这个Javascript闭包的例子:

对内部函数function(x)来讲,y就是自由变量,而且function(x)的返回值,依赖于这个外部自由变量

y。而往上推一层,外围Add(y)函数正好就是那个包含自由变量y的环境。而且Javascript的语法允

许内部函数function(x)访问外部函数Add(y)的局部变量。满足这三个条件,所以这个时候,外部函

数Add(y)对内部函数function(x)构成了闭包。

闭包的结构,如果用λ演算表达式来写,就是多参数的Currying技术。

>λx.λy.x+y

但在Java中我们看不到这样的结构。因为Java主流语法不允许这样的直接的函数套嵌和跨域访问变量。

2.
类和对象

但Java中真的不存在闭包吗?正好相反,Java到处都是闭包,所以反而我们感觉不出来在使用闭

包。因为Java的“对象”其实就是一个闭包。其实无论是闭包也好,对象也好,都是一种数据封装的

手段。看下面这个类

看上去x在函数add()的作用域外面,但是通过Add类实例化的过程,变量”x“和数值”2“之间已经绑

定了,而且和函数add()也已经打包在一起。add()函数其实是透过this关键字来访问对象的成员字

段的。

如果对闭包有疑问,可以看这个更详细的回答:

闭包(计算机科学)是什么?
- 胖胖的回答

3.
Java内部类是闭包:包含指向外部类的指针

那Java里有没有除了实例对象之外的闭包结构?Java中的内部类就是一个典型的闭包结构。例子如下,

下图画的就是上面代码的结构。内部类(Inner
Class)通过包含一个指向外部类的引用,做到自

由访问外部环境类的所有字段,变相把环境中的自由变量封装到函数里,形成一个闭包。

4.
别扭的匿名内部类

但Java匿名内部类就做得比较尴尬。下面这个例子中,getAnnoInner负责返回一个匿名内部类的引用。

匿名内部类因为是匿名,所以不能显式地声明构造函数,也不能往构造函数里传参数。不但返回的只是个叫AnnoInner的接口,而且还没有和它外围环境getAnnoInner()方法的局部变量x和y构成任何类的结构。但它的addXYZ()函数却直接使用了x和y这两个自由变量来计算结果。这就说明,外部方法getAnnoInner()事实上已经对内部类AnnoInner构成了一个闭包。

但这里别扭的地方是这两个x和y都必须用final修饰,不可以修改。如果用一个changeY()函数试图修改外部getAnnoInner()函数的成员变量y,编译器通不过,

error:
cannot assign a value to final variable y

这是为什么呢?因为这里Java编译器支持了闭包,但支持地不完整。说支持了闭包,是因为编译器编译的时候其实悄悄对函数做了手脚,偷偷把外部环境方法的x和y局部变量,拷贝了一份到匿名内部类里。如下面的代码所示。

所以用R大回答里的原话说就是:

Java编译器实现的只是capture-by-value,并没有实现capture-by-reference。

而只有后者才能保持匿名内部类和外部环境局部变量保持同步。

但Java又不肯明说,只能粗暴地一刀切,就说既然内外不能同步,那就不许大家改外围的局部变量。

5.
其他和匿名内部类相似的结构

《Think
in Java》书里,只点出了匿名内部类来自外部闭包环境的自由变量必须是final的。但实际上,其他几种不太常用的内部类形式,也都有这个特性。

比如在外部类成员方法内部的内部类。

比如在一个代码块block里的内部类。

java为什么匿名内部类的参数引用时final(转)的更多相关文章

  1. java提高篇(十)-----详解匿名内部类 ,形参为什么要用final

    在java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意的事项.如何初始 ...

  2. 为什么匿名内部类参数必须为final类型(转载)

    为什么匿名内部类参数必须为final类型转自于:http://feiyeguohai.iteye.com/blog/1500108 1)  从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类 ...

  3. JAVA方法中的参数用final来修饰的原因

    JAVA方法中的参数用final来修饰的原因   很多人都说在JAVA中用final来修饰方法参数的原因是防止方法参数在调用时被篡改,其实也就是这个原因,但理解起来可能会有歧义,有的人认为是调用语句的 ...

  4. JAVA核心:内存、比较和Final

    1.java是如何管理内存的 java的内存管理就是对象的分配和释放问题.(其中包括两部分) 分配:内存的分配是由程序完成的,程序员需要通过关键字new为每个对象申请内存空间(基本类型除外),所有的对 ...

  5. Java基础 匿名内部类 异常 多线程 集合面试题

    匿名内部类:没有名字的内部类.就是内部类的简化形式.一般只用一次就可以用这种形式.匿名内部类其实就是一个匿名子类对象.想要定义匿名内部类:需要前提,内部类必须继承一个类或者实现接口. 匿名内部类的格式 ...

  6. 详解匿名内部类 ,形参为什么要用final

    一.使用匿名内部类内部类 匿名内部类由于没有名字,所以它的创建方式有点儿奇怪.创建格式如下: new 父类构造器(参数列表)|实现接口() { //匿名内部类的类体部分 } 在这里我们看到使用匿名内部 ...

  7. 【Java学习笔记之二十】final关键字在Java继承中的用法小结

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法. ...

  8. Java:方法的参数是传值还是传引用

    Java中方法的参数总是采用传值的方式. 下列方法欲实现对象的交换,但实际上是不能实现的. public void swap(simpleClass a,simpleClass b){ simpleC ...

  9. Java中的可变参数以及foreach语句

    Java中的可变参数的定义格式如下: 返回值类型  方法名称(类型 ... 参数名称){} foreach语句的格式如下: for ( 数据类型  变量名称 :数据名称){ ... } public ...

随机推荐

  1. GinKgoCTF-Misc

    一:谁动了我的校徽? Jpg改txt——>寻找——>GKCTF{This_is_a_huaji} 二:奇怪的压缩包1 六位数字的密码一点也不安全!!!!!! 下载压缩包——>有密码( ...

  2. 【HDOJ4635】【Tarjan缩点+思维】【经典】

    http://acm.hdu.edu.cn/showproblem.php?pid=4635 Strongly connected Time Limit: 2000/1000 MS (Java/Oth ...

  3. easyui表单校验

    痛苦使人清醒,痛苦使人警惕.生于忧患,死于安乐.付出总会有回报. 1.下面跟大家分享使用easyui时表单中的值如何校验. 1.1 首先,在你的jsp/html页面引入JQuery和easyui的js ...

  4. LG3809 【模板】后缀排序

    题意 题目背景 这是一道模板题. 题目描述 读入一个长度为 $ n $ 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的 ...

  5. nakadi-ui nakadi event broker 的可视化UI工具

    nakadi 是一款很不错的基于fafka 开发的event broker ,我们只需要使用http 请求就可以调用kafka 方便的发布订阅功能 环境准备 docker-compose 文件 ver ...

  6. jsp与servlet的区别与联系

    jsp和servlet的区别和联系:1.jsp经编译后就变成了Servlet.(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能 ...

  7. Python3:sorted()函数及列表中的sort()函数

    一.sort,sorted函数介绍:   Sort函数是list列表中的函数,而sorted可以对list或者iterator进行排序.   下面我们使用help来查看他们的用法及功能: sort: ...

  8. PHP socket 服务器框架集

    1.Swoole:重新定义PHP PHP语言的高性能网络通信框架,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时 ...

  9. Day 01 计算机组成和操作系统

    一.编程与编程语言 1.什么是语言?什么是编程语言? 答:语言是一种事物与另一种事物沟通的介质. 编程语言是程序员与计算机沟通的介质. 2.什么是编程? 答:程序员把自己想要让计算机做的事用编程语言表 ...

  10. SourceInsight宏插件1(非常好用,强力推荐)

    对于一直使用sourceinsight编辑C/C++代码的工程师们,sourceinsight是一个非常好用的编辑工具可以任意定位,跳转,回退,本人一直使用该工具做C/C++开发,sourceinsi ...