java 板


LINE

※ 引述《egheee (阿平)》之銘言: : class A { : void tell() { : Log.e("", "I am a"); : } : } : class B extends A{ : void tell() { : Log.e("", "I am b"); : } : } : class C extends B { : void tell() { : super.super.tell(); // 問題 : Log.e("", "I am c"); : } : } : 如上列所示,這樣的寫法是有問題的,super好像規定只能用一次 : 請問我要怎麼從C裡面call到A的tell()呢? 依所示的情境與需求,就我所知是無法單從 Java 語法層面去解決的。 有些版友提到在 C::tell method 裡另外建構一個 A instance,由此 instance 去調用 tell method。我想這應該只能針對上面範例之類的個案(tell method 對 調用的 object 本身沒有副作用),能適用的實例不多,不能算是一種解法。 如果不限制在語法層面,也暫時不考慮這樣的設計是否合理...等等,的確是有方式 可以轉寰的。我提供一個的可行做法是透過 bytecode 工程去加工。 先定義一下需求與條件,以上述的 sample 來說: 1. 你沒有 class A, class B 的 source code,只有 class file。 2. 有 class C 的 source 可供編輯。 3. 基於某種因素,你需要明確在 C::tell method 裡調用 A::tell implemention, 不論 C 的 base classes 有無 override tell method。 我做了一個 bytecode 加工的工具,可在此網址下載(jar file): http://ul.to/2k6o1dzz 將 C.java 修改為: import ptt.java.tool.RedirectSuperCall; class C extends B { @RedirectSuperCall(targetType=A.class) void tell() { super.tell(); Log.e("", "I am c"); } } 編譯 C.java 時將下載的 jar 加入 classpath。 編譯完後,執行 jar 內的 ptt.java.tool.Main class,執行時 classpath 除了 下載的 jar 外也需要包含你的 project binary(你的 project class file 不能 打包成 jar)。 java -cp <path_to_RedirectSuper.jar>;<project_output> ptt.java.tool.Main <path_to_C.class> 後面參數可以是(多個)檔案或檔案夾的路徑,如果檔案是 .class 檔案,tool 會去 看是否有使用 RedirectSuperCall annotation 來做加工,如果是檔案夾則會查看 檔案夾內的所有 .class 檔案(包括子檔案夾)。 為了比較快做出這個 tool 我有省略一些考量,算是比較簡化的版本。暫不考慮 generic method 以及 method exception clause,但 return type 與 parameter type/數量倒是沒有限制。 這個 tool 做的事情如下: 去修改以 RedirectSuperCall(targetType=XXX.class) 標注的 method bytecode (假設被標注的 method 是 someMethod),將 super.someMethod(...) expression 改成 invoke tool 注入在 XXX class 內的 static someMethod$hook method。 (被注入的 method 內容大致如下: class XXX { public static ... someMethod$hook(XXX obj, ...) { return obj.someMethod(...); // but use invokespecial instruction } } 雖然說 annotation 只標注在 C class,但是單只是去加工 C class bytecode 是 不足以做所需的效果,若是把 super.someMethod(...) expression 中 invokespecial instruction 的目標 class 從 B 改成 A,還是會執行到 B class 定義的 overriding 版本。(因為此時的 context 是 C class) 我的做法是把原來的 invokespecial call 改成一個 invokestatic call,而被 指定的 method 裡使用 invokespecial instruction 來調用真正想要調用的 non-static virtual method。 這裡 hook method 簡單地透過 invokespecial instruction 調用另一個 virtual method 的做法應該是比較不保險的做法,但我在幾種 JRE 上測試過都正確。 (如果有人測試時沒有成功 redirect,歡迎來信告知/分享你使用的 JRE) 比較保險的做法是把目標 method inline 在 hook method 裡,但若是 targetType 並沒有真的 declare/override 被標注的 method,實作上會很麻煩。所以是我偷懶 沒錯,但是額外好處是 targetType 可以指定任一個 base class,他的意思是 「我要 redirect 到 targetType 為止的最新版本」。 *tool bytecode version 是 50.0,故你需要 JRE 1.6+ 才能使用之。 **理論上,這個 tool 應該可以做成 annotation processor 成為編譯的一部份, 或是做成 instrumentation agent 在 runtime 時部署。前者我經驗還不夠,要搞 比較久;後者則是因為當 JVM 載入使用 annotation 標記的 class 時,他的 base class 已經載入,如果還要加工 base class 的話,必須要使用的 JVM 有支援 retransform。所以我做出了這樣的工具...呵呵,反正只是 demo 用途。 --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 1.172.233.127
※ 文章網址: http://webptt.com/m.aspx?n=bbs/java/M.1420214806.A.11E.html







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:iOS站內搜尋

TOP