java中一个引人深思的匿名内部类
前两天去面试javaweb问到一个问题,在你的项目中有没有用到线程,我特么的一想,这东西不是在c层面的吗,所以说我不了解线程。。。。。
后来回去想啊想啊,我操这特么的不是再问我事物的控制,消息队列的回调?这特么的是什么面试
下面写出我这两天的答案,另附文章比较长大部分都是引用书本或个人博客
程序要靠上下文(context)来描述当前做的工作,防止忽略之前的数据,当然我们学习也要有个铺垫
在此列出以便有些我没有讲到的知识被忽略
[多问几个为什么]为什么匿名内部类中引用的局部变量和参数需要final而成员字段不用?
JAVA闭包
java基础:熟悉3种内部类的写法,重点匿名内部类的使用
阻塞,还是回调? 我眼中的skynet
java事务 深入Java事务的原理与应用
lua5.1手册
Programming in Lua
首先让我想起lua语言中闭包
有个疑问:闭包(Closures)内的变量可以保存原值, 那它什么时候释放掉呢
function newCounter()
local i =;
return function() --anonymous function
i = i +1;
return i;
end
end
c1= newCounter();
print(c1());-->1
print(c1());-->2
匿名函数内的i,既不是局部变量,也不是全局变量,i被一个叫upvalue保存,他保存在哪呢,
局部方法,局部变量 ,其实引用的是外部那个local i
lua的变量是垃圾回收的,那个i每调用一次newCounter就会新建一个。
所以那个返回的匿名函数就会绑定到这个新键的i(即upvalue)
其实可以变通的理解,进入了newCounter函数并调用一次i,(并创建了一个新的upvalue i), print(c1()) 和print(c1()) 相当于调用 printnewCount()()) 和print(newCount()())都只进入了newCounter函数一次,并调用匿名函数2次
当然准确得是说是一个闭包,这个闭包的函数体就是i=i+1,所以每次调用一次就相当于把c1
这个闭包中的upvalue + 1,不会再调用newCounter'
学过c++的同学应该会接触到一个functor
class Counter {
public:
Counter() : i() {}
int operator () () {
return i++;
}
int i;
};
然后c1=newcounter就相当于
Counter c1;然后c1()就相当于调用了operator,upvalue就相当于上面c++代码中的i
lua和上面的代码的不同在于,i的生命期是gc维护的
闭包在上下文环境中提供很有用的功能,这一机制使得我们可以在 Lua 的函数世界 里组合出奇幻的编程技术。闭包也可用在回调函数中,比如在 GUI 环境中你需要创建一 系列 button,但用户按下 button 时回调函数被调用,可能不同的按钮被按下时需要处理 的任务有点区别。
更一般的做法是我们使用匿名函数作为作为参数
技术上来讲,闭包指值而不是指函数,函数仅仅是闭包的一个原型声明;尽管如此, 在不会导致混淆的情况下我们继续使用术语函数代指闭包
从上面我们可以引出迭代器的概念
迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。在 Lua 中我们 常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。
给个例子
function list_iter (t)
local i =
local n = table.getn(t)
return function ()
i = i +
if i <= n then return t[i] end
end
end
t = {, , }
iter = list_iter(t) -- 初始化一个迭代
while true do
local element = iter() -- 调用这个迭代
if element == nil then break end
print(element)
end
--用于for
t = {10, 20, 30}
for element in list_iter(t) do
print(element)
end
范性 for 为迭代循环处理所有的薄记(bookkeeping):首先调用迭代工厂;内部保留 迭代函数,因此我们不需要 iter 变量;然后在每一个新的迭代处调用迭代器函数;当迭 代器返回 nil 时循环结束
迭代器的名字有一些误导,因为它并没有迭代,完成迭代功能的是 for 语句,也许是在其他语言比如 java、C++迭代器的说法已经很普遍了, 我们也将沿用这种术语。
一个完整的迭代器
function allwords (f)
-- repeat for each line in the file
for l in io.lines() do
-- repeat for each word in the line
for w in string.gfind(l, "%w+") do
-- call the function
f(w)
end
end
end
--如果我们想要打印出单词,只需要
allwords(print)
--更一般的做法是我们使用匿名函数作为作为参数,下面的例子打印出单词'hello'出现
的次数:
local count =
allwords(function (w)
if w == "hello" then count = count + end
end)
print(count)
--用 for 结构完成同样的任务:
local count =
for w in allwords() do
if w == "hello" then count = count + end
end
print(count)
两种风格的写法相差不大,但也有区别:一方面,第二种风格更容易书写和 方面,for 结构更灵活,可以使用 break 和 continue 语句;在真正的迭代器风格写法 中 return 语句只是从匿名函数中返回而不是退出循环
lua中不像大型数据语言java、c++你可以控制对象成员变量或 者成员方法是否私有。lua并没有定位到大型程序设计,通常是作为大型系统的一部分
例如下面的例子我们可以使用这种方式变相的实现一个私有的数据
设计的基本思想是,每个对象用两个表来表示:一个描述状态;另一个描述操作(或者 叫接口)。对象本身通过第二个表来访问,也就是说,通过接口来访问对象。为了避免未 授权的访问,表示状态的表中不涉及到操作;表示操作的表也不涉及到状态,取而代之 的是,状态被保存在方法的闭包内。
function newAccount (initialBalance)
local self = {balance = initialBalance}
local withdraw = function (v)
self.balance = self.balance - v
end
local deposit = function (v)
self.balance = self.balance + v
end
local getBalance = function () return self.balance end
return {
withdraw = withdraw,
deposit = deposit,
getBalance = getBalance
}
end
--[[这儿的关键点在于:这
些方法没有使用额外的参数 self,代替的是直接访问 self。因为没有这个额外的参数,我
们不能使用冒号语法来访问这些对象。函数只能像其他函数一样调用:]]
acc1 = newAccount(100.00)
acc1.withdraw(40.00)
print(acc1.getBalance()) --> 60
下面来一个方法私有化的例子
例如,我们的账号可以给某些用户取款享有额外的 10%的存款上限,但是我们不想 用户直接访问这种计算的详细信息,我们实现如下:
function newAccount (initialBalance)
local self = {
balance = initialBalance,
LIM = 10000.00,
}
local extra = function ()
if self.balance > self.LIM then
return self.balance*0.10
else
return
end
end
local getBalance = function ()
return self.balance + self.extra()
end
---------------------------------------------
--[[此段代码并没有写完,但是通过上面这段,我们就可以知道extra方法不会对外部曝光,这样,对于用户而言就没有办法直接访问 extra 函数了。]]
引人深思的单例模式由此而生
,-----------------写到这有了一些深恶痛绝的醒悟,这些与java的匿名内部类有关联吗--------------------------------
不说了,继续写
--[[关于 single-method 的对象一个有趣的情况是:当这个 single-method 实际是一个基于
重要的参数而执行不同的任务的分派(dispatch)方法时。针对这种对象:]]
function newObject (value)
return function (action, v)
if action == "get" then return value
elseif action == "set" then value = v
else error("invalid action")
end
end
end
--使用起来很简单:
d = newObject()
print(d("get")) --> 0
d("set", )
print(d("get")) --> 10
这种方式没有继承但有私有性:访问对象状态的唯一方式是通过它的内部方法。
其实上面这段代码,牵扯甚多闭包的应用,这就需要一个coroutine例子来考虑了
先付个链接https://www.zybuluo.com/wsd1/note/623964
-----------------------------------------------------后续----------------------------------------------------------------------------------
下面我们了解下java中的匿名内部类、内部类都满足什么条件才算是
1,、匿名内部类可以使用外部类的变量
2、匿名内部类中不同的方法可以共享这些变量
3、是引用了自由变量的函数。这个函数通常被定义在另一个外部函数中,并且引用了外部函数中的变量。
4、返回了可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。
5、 是一个匿名的代码块,可以接受参数,并返回一个返回值,也可以引用和使用在它周围的,可见域中定义的变量
6、是一个表达式,它具有自由变量及邦定这些变量的上下文环境。
7、闭包允许你将一些行为封装,将它像一个对象一样传来递去,而且它依然能够访问到原来第一次声明时的上下文。
8、 是指拥有多个变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
9、 闭包是可以包含自由(未绑定)变量的代码块;这些变量不是在这个代码块或者任何全局上下文中定义的,而是在定义代码块的环境中定义。
大家都知道闭包的概念在javascript中应用最为广泛,最多的是从一个回调函数来处理用户的异步事件,这些看起来都是非常抽象难以理解,其实你可以了解下jquery中ajax函数的定义,运用回调函数来处理用户的一些事件触发
举一个简单的例子你可能在上面的连接中看到了,适合人思考方式的程序是顺序事务的,比如做个西红柿炒蛋,切西红柿->热油->下锅炒,程序一般写成那样顺序的,最符合直觉。
但是你在定义这个程序的时候不可能不考虑一些开销,这就引出了一个事件,切好西红柿没有油了就得去买,就得悬挂起现场等着。
那么怎么挂起这个现场呢,程序语言对这个问题的不同解决方法,形成了各种语言不同的风格。
低级语言,会考虑使用寄存器来实现放进堆保存
高级语言(解释型或虚拟机)也是使用阻塞式和回调式来处理事件等候这个问题
高级语言中回调过程处理现场往往是通过语言特征对状态做缓存处理,用一个比较学术的名词描述,就是“闭包(closure)”。javascript就是这类的典型,来看一个例子
<script type="text/javascript">
function f1() {
var n = 99;
return function(){
alert(n);
};
}
f1();
</script>
f1的局部变量可以通过返回的匿名内部类funcion()调用,
今天先写这些,后续
java中一个引人深思的匿名内部类的更多相关文章
- java中一个字符串是另外一个字符串的字串
java中一个字符串是另外一个字符串的字串 String类中有一个方法 public boolean contains(Sting s)就是用来判断当前字符串是否含有参数指定的字符串例s1=“take ...
- Java中接口式的匿名内部类的构造方法
在使用多线程的时候,时常会使用两种方式实现,一种是直接继承Thread类来实现多线程,另外一种就是实现Runnable接口. 我们都知道,接口是没有构造方法的,同时匿名内部类也是没有构造方法的.原因有 ...
- java中一个重要思想:面向对象
面向对象: 1, 面向过程的思想(合适的方法出现在合适的类里面) 准备去一个地方: 先买车, 挂牌, 开导航, 踩油门, 过黄河, 穿越珠穆朗玛峰... 2, 面向对象的思想 我开着车去, 车怎么去随 ...
- Java中一个线程只有六个状态。至于阻塞、可运行、挂起状态都是人们为了便于理解,自己加上去的。
java中,线程的状态使用一个枚举类型来描述的.这个枚举一共有6个值: NEW(新建).RUNNABLE(运行).BLOCKED(锁池).TIMED_WAITING(定时等待).WAITING(等待) ...
- 为什么Java中一个char能存下一个汉字
在Java中,char的长度是2字节,即16位,2的16次方是65536. 1.如果采用utf-8编码,一个汉字占3个字节,char为什么还能存下一个汉字呢? 参考:https://developer ...
- java中一个数组不能放不同数据类型的值
在java中,数组不能放不同数据类型的值. 方法一: 多态 定义数组类型的时候定义为父类,而存进数组为父类的子类 public class test2 { public static void mai ...
- Java中的内部类与匿名内部类总结
内部类 内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类 如同一个人是由大脑.肢体.器官等身体结果组成,而内部类相当于其中的某个器官之一,例如心脏:它也有自己的属性和行为(血液.跳动) ...
- java中一个查询业务的流程
因为有用到分页,首先建一个page类 1 public class Page<T> { 2 private int pageSize; //每页显示条数 3 private int cur ...
- java 中一个char包含几个字节
背景 char包含几个字节可能记得在上学的时候书上写的是2个字节,一直没有深究,今天我们来探究一下到底一个char多少个字节? Char char在设计之初的时候被用来存储字符,可是世界上有那 ...
随机推荐
- session不会过期
$(function () { window.setInterval(function () { $.post('random.html'); }, 60000); }); 加在母版页里,使用与长时间 ...
- python更新数据库脚本两种方法
最近项目的两次版本迭代中,根据业务需求的变化,需要对数据库进行更新,两次分别使用了不同的方式进行更新. 第一种:使用python的MySQLdb模块利用原生的sql语句进行更新 import MySQ ...
- java异常处理、多态
第一:GC是什么? 为什么要有GC? 第二:垃圾回收的优点和原理.并考虑2种回收机制. 第三:垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收? 第 ...
- 快速排序(QuickSort)
1.算法思想 快速排序是一种划分交换排序.它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod). (1) 分治法的基本思想 分治法的基本思想是:将原 ...
- uboot 添加hello命令
平台:MPC8315(POWERPC) 1.在/common/ 目录下创建自己的文件,最好前缀为cmd_. cmd_hello.c ********************************** ...
- R语言︱逻辑运算
R软件包含两个逻辑值,TRUE和FALSE.在其他编程语言中也称为布尔值(Boolean values).布尔向量就是充满着逻辑值的逻辑向量.那么有如何的应用呢? 1.比较运算可以产生逻辑值 > ...
- echarts中地图提示"TypeError:i is undefined"
1.错误描述 2.错误原因 刚开始地图的数据源是由静态数据提供,后来修改成从数据库中获取,请求数据的方法成功后调用地图方法,但是初始化时未调用数据请求方法,导致地图核心js报错 3.解决办法 初始化时 ...
- freemarker写select组件(三)
freemarker写select组件 1.宏定义 <#macro select id datas value="" key="" text=" ...
- 如何在BIOS中设置RAID?
随着价格的下降和相应主板的支持,目前SATA硬盘已经逐渐成为主流.但由于受芯片组和操作系统的影响,不少用户对SATA硬盘的使用及安装系统掌握不足,今天小编就给大家介绍一下SATA硬盘的日常应用技巧,希 ...
- 一款PHP环境整合工具—VertrigoServ介绍
Vertrigo简介 VertrigoServ 是一个Windows平台下的非常专业的.易于安装的免费网络开发环境,它集成了Apache, PHP, MySQL, SQLite, SQLiteMana ...