最近看了下Jacoco源码,对插装后的代码反编译,有看到定义$jacocoInit()方法,但无法反编译具体实现。通过阅读官方文档以下说明:
Object access = ... // Retrieve instance
Object[] args = new Object[3];
args[0] = Long.valueOf(8060044182221863588); // class id
args[1] = "com/example/MyClass"; // class name
args[2] = Integer.valueOf(24); // probe count
access.equals(args);
boolean[] probes = (boolean[]) args[0];
对于以上的实现非常困惑,args[0]是Long类型怎么能强制转换为boolean[]呢。
Jacoco是通过插入JVM指令实现$jacocoInit()的,其中有个equals的方法特别容易让人难以理解,equals内部对数组进行了修改。通过对JVM指令的还原,伪代码示意如下。
public class User {
private static transient boolean[] $jacocoData;
private String name;
public User(String name) {
boolean[] var2 = $jacocoInit();
super();
this.name = name;
var2[0] = true;
}
public String getName() {
boolean[] var1 = $jacocoInit();
var1[1] = true;
return this.name;
}
public void setName(String name) {
boolean[] var2 = $jacocoInit();
this.name = name;
var2[2] = true;
}
private static boolean[] $jacocoInit() {
if($jacocoData != null){
return $jacocoData;
}
{ // 如果使用:SystemPropertiesRuntime存储执行信息,会从以下方式获取
java.util.Properties properties = java.lang.System.getProperties();
RuntimeData data = (RuntimeData)properties.get("key+hashcode()");
Object[] args = new Object[3];
args[0] = Long.valueOf(8060044182221863588); // class id
args[1] = "com/example/MyClass"; // class name
args[2] = Integer.valueOf(24); // probecount
// 特殊方法,会修改args[0] 的值,参考RuntimeData.equals()
data.equals(args);
$jacocoData = (boolean[])args[0];
}
return $jacocoData;
}
}