java 中 可以使用assert语法来进行一些判断检,但是 android上 assert似乎不生效, 这是为什么呢。
在将java source code编译成class文件的过程中,如果一个类中使用了assert语法,那么class文件中会生成一个static field。
final static synthetic Z $assertionsDisabled
在类的静态初始化函数,会生成以下代码
static <clinit>()V
L0
LINENUMBER 20 L0
LDC Lorg/chromium/base/JavaExceptionReporter;.class
INVOKEVIRTUAL java/lang/Class.desiredAssertionStatus ()Z
IFNE L1
ICONST_1
GOTO L2
L1
FRAME SAME
ICONST_0
L2
FRAME SAME1 I
PUTSTATIC org/chromium/base/JavaExceptionReporter.$assertionsDisabled : Z
RETURN
会先判断Class.desiredAssertionStatus()的返回值,如果是false, 设置assertionsDisabled为false。
android中 Class.desiredAssertionStatus() 的定义
public boolean desiredAssertionStatus() {
return false;
}
所以$assertionsDisabled会被设置为true。
真正使用assert的地,会被替换为
L0
LINENUMBER 55 L0
GETSTATIC org/chromium/base/JavaExceptionReporter.$assertionsDisabled : Z
IFNE L1
INVOKESTATIC "assert method"Z
IFNE L1
NEW java/lang/AssertionError
DUP
INVOKESPECIAL java/lang/AssertionError.<init> ()V
ATHROW
L1
LINENUMBER 59 L1
如果$assertionsDisabled 为false,则会先判断assert后面的值,如果是true,则会抛出 AssertionError异常,否则就执行后面的代码。
所以在Android要使assert生效,有两种方法:
-
adb shell setprop debug.assert 1
(只对dalvik虚拟机生,对art虚拟机不生效!) - 使用字节码修改工具,比如asm,用以下代码将赋值
$assertionsDisabled
的地方替换成POP 指令。
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (opcode == Opcodes.PUTSTATIC && name.equals("$assertionsDisabled")) {
super.visitInsn(Opcodes.POP); // enable assert
}
}