博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java中一个引人深思的匿名内部类
阅读量:6524 次
发布时间:2019-06-24

本文共 5403 字,大约阅读时间需要 18 分钟。

前两天去面试javaweb问到一个问题,在你的项目中有没有用到线程,我特么的一想,这东西不是在c层面的吗,所以说我不了解线程。。。。。

后来回去想啊想啊,我操这特么的不是再问我事物的控制,消息队列的回调?这特么的是什么面试

下面写出我这两天的答案,另附文章比较长大部分都是引用书本或个人博客

程序要靠上下文(context)来描述当前做的工作,防止忽略之前的数据,当然我们学习也要有个铺垫

在此列出以便有些我没有讲到的知识被忽略

lua5.1手册

Programming in Lua

 

首先让我想起lua语言中闭包

有个疑问:闭包(Closures)内的变量可以保存原值, 那它什么时候释放掉呢

function newCounter()    local i =0;    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(0) {}      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 = 0local n = table.getn(t)return function () i = i + 1 if i <= n then return t[i] endendendt = {
10, 20, 30}iter = list_iter(t) -- 初始化一个迭代while true dolocal 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 filefor 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)  endendend --如果我们想要打印出单词,只需要allwords(print) --更一般的做法是我们使用匿名函数作为作为参数,下面的例子打印出单词'hello'出现的次数:local count = 0allwords(function (w)if w == "hello" then count = count + 1 endend)print(count)--用 for 结构完成同样的任务:local count = 0for w in allwords() doif w == "hello" then count = count + 1 endendprint(count)

 

两种风格的写法相差不大,但也有区别:一方面,第二种风格更容易书写和 方面,for 结构更灵活,可以使用 break 和 continue 语句;在真正的迭代器风格写法 中 return 语句只是从匿名函数中返回而不是退出循环

 

lua中不像大型数据语言java、c++你可以控制对象成员变量或 者成员方法是否私有。lua并没有定位到大型程序设计,通常是作为大型系统的一部分

例如下面的例子我们可以使用这种方式变相的实现一个私有的数据

设计的基本思想是,每个对象用两个表来表示:一个描述状态;另一个描述操作(或者 叫接口)。对象本身通过第二个表来访问,也就是说,通过接口来访问对象。为了避免未 授权的访问,表示状态的表中不涉及到操作;表示操作的表也不涉及到状态,取而代之 的是,状态被保存在方法的闭包内。

function newAccount (initialBalance)local self = {balance = initialBalance}local withdraw = function (v) self.balance = self.balance - vendlocal deposit = function (v) self.balance = self.balance + vendlocal getBalance = function () return self.balance endreturn {  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 0 endendlocal 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") endendend--使用起来很简单:d = newObject(0)print(d("get")) --> 0d("set", 10)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就是这类的典型,来看一个例子

f1的局部变量可以通过返回的匿名内部类funcion()调用,

今天先写这些,后续

 

转载于:https://www.cnblogs.com/dmeck/p/8526245.html

你可能感兴趣的文章