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/cn.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灯, 水草

请输入看板名称,例如:Gossiping站内搜寻

TOP