java中一個引人深思的匿名內部類 JAVA閉包 java基礎:熟悉3種內部類的寫法,重點匿名內部類的使用

前兩天去面試javaweb問到一個問題,在你的項目中有沒有用到線程,我特麼的一想,這東西不是在c層面的嗎,因此說我不瞭解線程。。。。。javascript

後來回去想啊想啊,我操這特麼的不是再問我事物的控制,消息隊列的回調?這特麼的是什麼面試html

下面寫出我這兩天的答案,另附文章比較長大部分都是引用書本或我的博客java

程序要靠上下文(context)來描述當前作的工做,防止忽略以前的數據,固然咱們學習也要有個鋪墊jquery

在此列出以便有些我沒有講到的知識被忽略c++

[多問幾個爲何]爲何匿名內部類中引用的局部變量和參數須要final而成員字段不用?web

JAVA閉包

java基礎:熟悉3種內部類的寫法,重點匿名內部類的使用

阻塞,仍是回調? 我眼中的skynet

java事務 深刻Java事務的原理與應用

lua5.1手冊面試

Programming in Luaajax

 

首先讓我想起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 = 0
local n = table.getn(t)
return function ()
 i = i + 1
 if i <= n then return t[i] end
end
end
t = {10, 20, 30}
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 = 0
allwords(function (w)
if w == "hello" then count = count + 1 end
end)
print(count)
--用 for 結構完成一樣的任務:
local count = 0
for w in allwords() do
if w == "hello" then count = count + 1 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 0
 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(0)
print(d("get")) --> 0
d("set", 10)
print(d("get")) --> 10 

這種方式沒有繼承但有私有性:訪問對象狀態的惟一方式是經過它的內部方法。

 

其實上面這段代碼,牽扯甚多閉包的應用,這就須要一個coroutine例子來考慮了

先付個連接https://www.zybuluo.com/wsd1/note/623964

-----------------------------------------------------後續----------------------------------------------------------------------------------

 

下面咱們瞭解下java中的匿名內部類、內部類都知足什麼條件纔算是

1,、匿名內部類可使用外部類的變量

二、匿名內部類中不一樣的方法能夠共享這些變量

 

三、是引用了自由變量函數。這個函數一般被定義在另外一個外部函數中,而且引用了外部函數中的變量。

四、返回了可調用的對象,它記錄了一些信息,這些信息來自於建立它的做用域

五、 是一個匿名的代碼塊,能夠接受參數,並返回一個返回值,也能夠引用和使用在它周圍的,可見域中定義的變量

六、是一個表達式,它具備自由變量及邦定這些變量的上下文環境

七、閉包容許你將一些行爲封裝,將它像一個對象同樣傳來遞去,並且它依然可以訪問到原來第一次聲明時的上下文

八、 是指擁有多個變量和綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是該表達式的一部分。

九、 閉包是能夠包含自由(未綁定)變量代碼塊;這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義。

 

你們都知道閉包的概念在javascript中應用最爲普遍,最多的是從一個回調函數來處理用戶的異步事件,這些看起來都是很是抽象難以理解,其實你能夠了解下jquery中ajax函數的定義,運用回調函數來處理用戶的一些事件觸發

 

舉一個簡單的例子你可能在上面的鏈接中看到了,適合人思考方式的程序是順序事務的,好比作個西紅柿炒蛋,切西紅柿->熱油->下鍋炒,程序通常寫成那樣順序的,最符合直覺。

可是你在定義這個程序的時候不可能不考慮一些開銷,這就引出了一個事件,切好西紅柿沒有油了就得去買,就得懸掛起現場等着。

那麼怎麼掛起這個現場呢,程序語言對這個問題的不一樣解決方法,造成了各類語言不一樣的風格。

低級語言,會考慮使用寄存器來實現放進堆保存

高級語言(解釋型或虛擬機)也是使用阻塞式和回調式來處理事件等候這個問題

高級語言中回調過程處理現場每每是經過語言特徵對狀態作緩存處理,用一個比較學術的名詞描述,就是「閉包(closure)」。javascript就是這類的典型,來看一個例子

<script type="text/javascript">
            function f1() {
                var n = 99;
               return function(){
          alert(n);
          }; } f1();
</script>

f1的局部變量能夠經過返回的匿名內部類funcion()調用,

今天先寫這些,後續

相關文章
相關標籤/搜索