最近看了js的閉包,仔細想了想,感覺java也可以模擬js的閉包特性實現屬性封裝,不過看似沒什麼卵用。
下面,首先定義一個Person類,該類中並沒有任何屬性,我們將屬性 pname和page放到一個靜態方法中,作爲局部變量,對!你沒有看錯,局部變量!
然後用lambda表達式來set或get 這些局部變量。
最後將這些lambda表達式(匿名內部類)放入一個map中做爲返回值返回。
具體代碼如下:
package com.fly.domain;
import java.util.HashMap;
import java.util.Map;
public class Person {
//靜態方法獲取Person的操作接口
public static Map<String, PersonInterface> getPerson() {
//定義局部變量 pname和page
String[] pname = new String[1];
Integer[] page = new Integer[1];
//定義操作局部變量的接口
PersonInterface getName = (v) -> {
return pname[0];
};
PersonInterface getAge = (v) -> {
return page[0];
};
PersonInterface setName = (v) -> {
pname[0] = (String) v;
return null;
};
PersonInterface setAge = (v) -> {
page[0] = (Integer) v;
return null;
};
//將操作接口放入map
Map<String, PersonInterface> person = new HashMap<>();
person.put("setName", setName);
person.put("setAge", setAge);
person.put("getName", getName);
person.put("getAge", getAge);
//返回接口map
return person;
}
//定義一個函數式接口,用於lambda表達式
public static interface PersonInterface {
Object apply(Object value);
}
}
下面測試下這個四不像的類吧:
public static void main(String[] args) {
//做倆Person出來(其實是兩個Map,內部封裝了操作pname和page的接口)
Map<String, Person.PersonInterface> p1 = Person.getPerson();
Map<String, Person.PersonInterface> p2 = Person.getPerson();
//給屬性賦值
p1.get("setName").apply("老王");
p1.get("setAge").apply(66);
p2.get("setName").apply("老李");
p2.get("setAge").apply(55);
//輸出
Object name1 = p1.get("getName").apply(null);
Object age1 = p1.get("getAge").apply(null);
System.out.println("p1.name = " + name1 + ", and p1.age = " + age1);
Object name2 = p2.get("getName").apply(null);
Object age2 = p2.get("getAge").apply(null);
System.out.println("p2.name = " + name2 + ", and p2.age = " + age2);
}
輸出結果:
p1.name = 老王, and p1.age = 66
p2.name = 老李, and p2.age = 55
目前看來,這種方法確實可以封裝屬性,(值得注意的是:封裝的屬性我用了數組來實現,因爲lambda表達式內部無法修改外部變量,我只能採用間接的方法來實現)但是不知道爲什麼匿名內部類會把一個方法內部的局部變量給帶到外邊來,關鍵是:這是否會影響垃圾回收。
不過這種方法的確把屬性封裝的死死的,似乎暴力反射也取不出來。底層原理還在研究中。。。
更新,關於原理初步探討
廢話不多說,上圖:
可以看到,所有的Lambda表達式都被編譯成了一個
Person$lambda
的內部類(其中Person是該lambda表達式所在的類),其內部封裝了一個屬性:**arg$1**
,看來,這個屬性就是lambda表達式攜帶的局部變量!!!
從圖中可以看出,“老王”,“66”這些屬性都被封裝到了lambda表達式內部,作爲成員屬性。