反编译工具并不能完全地把字节码反编译成Java代码,因此有的字节码反编译后的代码中会出现一些JVM指令。下面通过这几个例子讲解下。
1. 下面代码是从商业项目SwisSQL的SQLCache类反编译以后的一段代码:
public static String getConvertedSQL(String gvnSQL){
try{
PUSH(String)SQLTable.get(gvnSQL);
}catch(Exceptione){
returnnull;
}
returnPOP;
}
其中“PUSH(String)SQLTable.get(gvnSQL);”这句的意思是把SQLTable.get(gvnSQL)的返回值压栈,最后一句就是把刚才压入栈中的值弹出来并返回。其等效于:
publicstatic String getConvertedSQL(String gvnSQL){
Stringstr=null;
try{
str=(String)SQLTable.get(gvnSQL);
}catch(Exceptione){
return null;
}
returnstr;
}
2. 下面的代码是SWT-Designer的NameCheckTitleAreaDialog类反编译以后的一段:
public class NameCheckTitleAreaDialog extendsTitleAreaDialog{
staticClass class$0;
…..
protected intcheckName(String name,String checkMethodName){
……
PUSHclass$0;
DUP
If(POP==null){
POP
try
{
PUSH(Class.forName(“org.eclipse.jdt.internal.corext.refactoring.Checks”));
}catch(ClassNotFoundExceptionPUSH){
PUSH new NoClassDefFoundError;
DUP_X1
SWAP
((UNCONSTRUCTED)POP).NoClassDefFoundError(((Throwable)POP).getMessage());
throw POP;
}
PUSH class$0=POP;
}//endif
……..
3. 这里简单介绍几个常见的JVM指令:
DUP——复制栈顶值;
DUP2——将栈前两个值复制;
DUP_X1——复制栈顶值,并且将其下移两个位置。
DUP2_X1——将栈前两个值复制,并且将其下移两个位置。
DUP_X2——复制栈顶值,并且将其下移3个位置。
DUP2_X2——将栈前两个值复制,并且将其下移3个位置。
SWAP——交换栈中前两个值的位置
4. 简单解释下这里用到的JVM指令:
程序首先调用“PUSH class$0”将class$0压入栈,然后调用DUP将栈顶的值复制一份加入栈,此时栈中有两个class$0变量。
“if(POP==null)”:首先”POP”出栈,判断此变量(即class$0)是否为空,如果否的话,则跳过此段代码,如果是的话,则首先执行”POP“将另一class$0变量弹出。调用”Class.forName(“org.eclipse.jdt.internal.corext.refactoring.Checks”)”反射取得Checks类对象,然后将类对象实例压栈,如果反射调用成功,则调用“PUSH class$0=POP;”将栈中的类对象弹出来赋值给class$0变量。
如果调用”Class.forName(“org.eclipse.jdt.internal.corext.refactoring.Checks”)”的时候发生异常,则”catch(ClassNotFoundExceptionPUSH)”这句会首先将捕捉到的异常变量压栈,”PUSH new NoClassDefFoundError;”是创建一个NoClassDefFoundError类变量(注意此处不是调用的NoClassDefFoundError的构造函数,所以并没有实例化,只是创建一个变量而已)然后压栈。
调用“DUP_X1”,将栈顶值(即NoClassDefFoundError的变量)复制一份并下移两个位置;调用“SWAP”交换栈前两个元素的位置。
“((UNCONSTRUCTED)POP).NoClassDefFoundError(((Throwable)POP).getMessage());”中,虽然代码的顺序是先”((UNCONSTRUCTED)POP)”后”.NoClassDefFoundError(((Throwable)POP).getMessage()”,但是真正的运行顺序是调用构造函数“.NoClassDefFoundError(((Throwable)POP).getMessage()”,在这里将“抛出的ClassNotFoundException异常的的实例”弹出来,调用其getMessage()得到String变量作为构造函数NoClassDefFoundError的变量“,由于栈中随后一个元素是刚才被初始化的副本,所以就可以把最后一个元素弹出Throw了。
5. 翻译后的代码如下:
public class NameCheckTitleAreaDialog extendsTitleAreaDialog{
staticClass class$0;
protectedint checkName(String name,String checkMethodName){
if(class$0==null){
try{
class$0=(Class.forName(“org.eclipse.jdt.internal.corext.refactoring.Checks”));
}catch(ClassNotFoundExceptione){
Thrownew NoClassDefFoundError(((Throwable)e).getMessage());
}
}
}