在這裡主要會提到如何透過Java Reflection存取private inner class,但是一個類別的private inner class本來就不是要給外部類別存取的,因此在這邊會搭配實際的範例說明為何我們可能需要去存取private inner class!
在這裡會建立三個class,兩個class在manager package下,另一個則是main package
+package - manager
InfoManager.java
InfoMain.java
+package - main
InnerPrivateClassReflection.java(主程式)
一、InfoManager.java
在此總共有三個inner class,AbstractInfo、InfoTmp皆為私有類別,InfoPermanent為公有類別再來InfoManager本身為singleton mode,所擔任的就是控制目前Info建立的情形,並且將它記錄到tmpInfos及recordInfos變數內。
那麼可以操作的動作如下:
基本上,這些動作如addInfo、updateInfo都會先產生InfoTmp的object,只有當做save的動作時才會建立InfoPermanent object,並且將暫存InfoTmp的變數clear掉!
二、InfoMain.java
再來則是透過InfoMain來進行addInfo及updateInfo針對InfoManager,而且InfoMain呼叫的displayAllInfo會包含尚未saved的Info,也就是包含tmpInfo也會在裡面!
PS. 部分針對manager呼叫的method為protected,因此需要同一個package下的class才可以呼叫!
三、InnerPrivateClassReflection.java
再來則是主程式,主程式會建立InfoMain object,並且進行addInfo、updateInfo
Display all not saved informations...
[param:${PARAM1}, value:-p 111 -t 222]
[param:${PARAM2}, value:-f 555 -g 888]
update ${PARAM1} value to -r 333 -u 666
Display all not saved informations...
[param:${PARAM1}, value:-r 333 -u 666]
[param:${PARAM2}, value:-f 555 -g 888]
上面的console output可以得知update前後的資料顯示
不過主程式本身是無法透過InfoManager來進行相關操作的,針對protected method。主程式呼叫InfoManager的displayAllInfo只能顯示已saved的Info! 所以,主程式呼叫getInfo所得到的資料也是舊的! 更別提想要存取到未儲存的${PARAM1}的value -r 333 -u 666
Console output:
InnerPrivateClassReflection get ${PARAM1} info
[param:${PARAM1}, value:-p 111 -t 222]
所以,假設主程式想要取得tmpInfo object的value,那麼又該怎麼辦? 因為一般透過Java Reflection要呼叫該object的method,首先需要建立Method object
如Method method = InfoManager.InfoTmp.class.getDeclaredMethod("getValue");
但是在主程式內無法利用InfoManager呼叫private的inner class!
因此在這邊會透過
Class<?> innerClass[] = InfoManager.class.getDeclaredClasses();
來取得InfoManager的inner class,再比對該class name是否是我們要的,以此取得class type
如下:
首先透過呼叫getTmpInfo來取得InfoTmp object,再比對哪一個class name是InfoTmp 而變數clazz還需要呼叫getSuperclass(),由於InfoTmp並沒有getValue() method,因此需要透過其父類別才可以!
PS. 取得InfoTmp object其實體為InfoTmp,但是其型態為AbstractInfo,因此變數clazz應也可以針對AbstractInfo,那麼此時clazz就可以直接呼叫getDeclaredMethod了
綜合上面的結果,最後執行如下:
總結
在這邊有點弔詭,針對未儲存的Info為何需要去get它的value呢?
假設InfoMain及InnerPrivateClassReflection是一個大dialog下的兩個不同頁面的功能,可以透過切換的方式到這兩個頁面。InfoMain這個頁面可以CRUD Info但是在切換至
InnerPrivateClassReflection頁面時可以不一定要儲存,而InnerPrivateClassReflection頁面內又需要即時取得Info最新的value,若在InnerPrivateClassReflection頁面取得的還是更改之前的就感覺沒有sync了,雖然說InfoMain還沒有存檔! 如此一來,為了達到sync的目的,即使是private inner class也要取得它的value才是!
但還是有點奇怪,那不就只要改InfoMain內相關的存取範圍就好了呀! 可惜的是,假設InfoMain是一個第三方核心的code且已經包在jar檔內,那麼當然採用前者的方式囉!
在這裡會建立三個class,兩個class在manager package下,另一個則是main package
+package - manager
InfoManager.java
InfoMain.java
+package - main
InnerPrivateClassReflection.java(主程式)
一、InfoManager.java
package manager;
public class InfoManager {
...
private Map<String, AbstractInfo> tmpInfos;
private Map<String, AbstractInfo> recordInfos;
private static InfoManager INSTANCE = new InfoManager();
private InfoManager() {
tmpInfos = new HashMap<String, AbstractInfo>();
recordInfos = new HashMap<String, AbstractInfo>();
}
public static InfoManager getInstance() {
return INSTANCE;
}
private abstract class AbstractInfo{
private String param;
private String value;
public AbstractInfo(String param, String value) {
super();
this.param = param;
this.value = value;
}
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public String toString() {
return "[param:"+param+", value:"+value+"]";
}
}
private class InfoTmp extends AbstractInfo{
public InfoTmp(String param, String value) {
super(param, value);
}
}
public class InfoPermanent extends AbstractInfo{
public InfoPermanent(String param, String value) {
super(param, value);
}
}
}
在此總共有三個inner class,AbstractInfo、InfoTmp皆為私有類別,InfoPermanent為公有類別再來InfoManager本身為singleton mode,所擔任的就是控制目前Info建立的情形,並且將它記錄到tmpInfos及recordInfos變數內。
那麼可以操作的動作如下:
protected void addInfo(String param, String value) {
InfoTmp tmp = new InfoTmp(param, value);
tmpInfos.put(param, tmp);
}
protected AbstractInfo getTmpInfo(String param) {
return tmpInfos.get(param);
}
protected void updateInfo(String param, String value) {
System.out.println("update "+param+" value to "+value);
tmpInfos.put(param, new InfoTmp(param, value));
}
public AbstractInfo getInfo(String param) {
return recordInfos.get(param);
}
public void displayAllInfo() {
System.out.println("Display all informations...");
for(String param : recordInfos.keySet()) {
System.out.println(recordInfos.get(param));
}
}
protected void displayAllNotSavedInfo() {
System.out.println("Display all not saved informations...");
for(String param : recordInfos.keySet()) {
if(tmpInfos.containsKey(param)) {
System.out.println(tmpInfos.get(param));
}else {
System.out.println(recordInfos.get(param));
}
}
}
public void save() {
//System.out.println("save....");
for(String param : tmpInfos.keySet()) {
AbstractInfo info = getTmpInfo(param);
recordInfos.put(param, new InfoPermanent(info.getParam(), info.getValue()));
}
tmpInfos.clear();
}
基本上,這些動作如addInfo、updateInfo都會先產生InfoTmp的object,只有當做save的動作時才會建立InfoPermanent object,並且將暫存InfoTmp的變數clear掉!
二、InfoMain.java
package manager;
public class InfoMain {
private InfoManager manager = InfoManager.getInstance();
public InfoMain() {
manager.addInfo("${PARAM1}", "-p 111 -t 222");
manager.addInfo("${PARAM2}", "-f 555 -g 888");
manager.save();
}
public void updateInfo(String param, String value) {
manager.updateInfo(param, value);
}
public void addInfo(String param, String value) {
manager.addInfo(param, value);
}
public void displayAllInfo() {
manager.displayAllNotSavedInfo();
}
}
再來則是透過InfoMain來進行addInfo及updateInfo針對InfoManager,而且InfoMain呼叫的displayAllInfo會包含尚未saved的Info,也就是包含tmpInfo也會在裡面!
PS. 部分針對manager呼叫的method為protected,因此需要同一個package下的class才可以呼叫!
三、InnerPrivateClassReflection.java
再來則是主程式,主程式會建立InfoMain object,並且進行addInfo、updateInfo
package main;
public class InnerPrivateClassReflection {
public static void main(String[] args) throws Exception {
InfoMain main = new InfoMain();
main.displayAllInfo();
main.updateInfo("${PARAM1}", "-r 333 -u 666");
main.displayAllInfo();
...
}
}
Console output:Display all not saved informations...
[param:${PARAM1}, value:-p 111 -t 222]
[param:${PARAM2}, value:-f 555 -g 888]
update ${PARAM1} value to -r 333 -u 666
Display all not saved informations...
[param:${PARAM1}, value:-r 333 -u 666]
[param:${PARAM2}, value:-f 555 -g 888]
上面的console output可以得知update前後的資料顯示
不過主程式本身是無法透過InfoManager來進行相關操作的,針對protected method。主程式呼叫InfoManager的displayAllInfo只能顯示已saved的Info! 所以,主程式呼叫getInfo所得到的資料也是舊的! 更別提想要存取到未儲存的${PARAM1}的value -r 333 -u 666
InfoManager manager = InfoManager.getInstance();
System.out.println("InnerPrivateClassReflection get ${PARAM1} info");
System.out.println(manager.getInfo("${PARAM1}"));
Console output:
InnerPrivateClassReflection get ${PARAM1} info
[param:${PARAM1}, value:-p 111 -t 222]
所以,假設主程式想要取得tmpInfo object的value,那麼又該怎麼辦? 因為一般透過Java Reflection要呼叫該object的method,首先需要建立Method object
如Method method = InfoManager.InfoTmp.class.getDeclaredMethod("getValue");
但是在主程式內無法利用InfoManager呼叫private的inner class!
因此在這邊會透過
Class<?> innerClass[] = InfoManager.class.getDeclaredClasses();
來取得InfoManager的inner class,再比對該class name是否是我們要的,以此取得class type
如下:
Method method = InfoManager.class.getDeclaredMethod("getTmpInfo", String.class);
method.setAccessible(true);
Object tmpInfo = method.invoke(manager, "${PARAM1}");
System.out.println("Call getTmpInfo() by Java Reflection\n"+tmpInfo);
Class innerClass[] = InfoManager.class.getDeclaredClasses();
for(Class clazz : innerClass) {
if(clazz.getSimpleName().equals("InfoTmp")) {
method = clazz.getSuperclass().getDeclaredMethod("getValue");
method.setAccessible(true);
Object obj = method.invoke(tmpInfo);
System.out.println(obj);
}
}
首先透過呼叫getTmpInfo來取得InfoTmp object,再比對哪一個class name是InfoTmp 而變數clazz還需要呼叫getSuperclass(),由於InfoTmp並沒有getValue() method,因此需要透過其父類別才可以!
PS. 取得InfoTmp object其實體為InfoTmp,但是其型態為AbstractInfo,因此變數clazz應也可以針對AbstractInfo,那麼此時clazz就可以直接呼叫getDeclaredMethod了
綜合上面的結果,最後執行如下:
總結
在這邊有點弔詭,針對未儲存的Info為何需要去get它的value呢?
假設InfoMain及InnerPrivateClassReflection是一個大dialog下的兩個不同頁面的功能,可以透過切換的方式到這兩個頁面。InfoMain這個頁面可以CRUD Info但是在切換至
InnerPrivateClassReflection頁面時可以不一定要儲存,而InnerPrivateClassReflection頁面內又需要即時取得Info最新的value,若在InnerPrivateClassReflection頁面取得的還是更改之前的就感覺沒有sync了,雖然說InfoMain還沒有存檔! 如此一來,為了達到sync的目的,即使是private inner class也要取得它的value才是!
但還是有點奇怪,那不就只要改InfoMain內相關的存取範圍就好了呀! 可惜的是,假設InfoMain是一個第三方核心的code且已經包在jar檔內,那麼當然採用前者的方式囉!
留言
張貼留言