如何以编程方式为特定类启用断言,而不是指定命令行参数“-ea”?
public class TestAssert {
private static final int foo[] = new int[]{4,5,67};
public static void main(String []args) {
assert foo.length == 10;
}
}
尝试
ClassLoader loader = getClass().getClassLoader();
setDefaultAssertionStatus(true);
或
ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
编辑:
基于评论
ClassLoader loader = ClassLoader.getSystemClassLoader();
loader.setDefaultAssertionStatus(true);
Class<?> c = loader.loadClass("MyClass");
MyClass myObj = (MyClass) c.newInstance();
public class MyClass {
private static final int foo[] = new int[]{4,5,67};
MyClass()
{
assert foo.length == 10;
}
}
这是对@bala 好的答案的评论,但它太长了。
如果您只是启用断言,然后调用您的主类 - 您的主类将在启用断言之前加载,因此您可能需要一个不直接引用代码中其他任何内容的加载器。 它可以设置断言,然后通过反射加载其余代码。
如果在加载类时未启用断言,那么它们应该立即“编译出来”,这样您就无法打开和关闭它们。 如果你想切换它们,那么你根本不需要断言。
由于运行时编译,会出现这样的情况:
public myAssertNotNull(Object o) {
if(checkArguments)
if(o == null)
throw new IllegalArgumentException("Assertion Failed");
}
应该几乎与断言一样快,因为如果代码被执行很多并且 checkArguments 为 false 并且不改变,那么整个方法调用可以在运行时编译出来,这将具有与断言相同的基本效果(此性能取决于在虚拟机上)。
可以使用 reflection 启用或禁用断言。与反射一样,该解决方案很脆弱,可能并不适合所有使用场景。但是,如果适用且可接受,它比
setClassAssertionStatus
更灵活,因为它允许在执行中的各个点启用/禁用断言检查,甚至在类初始化之后。
此技术需要编译器生成一个合成静态字段来指示是否启用断言。例如,javac 和 Eclipse 编译器都会为任何包含
$assertionsDisabled
语句的类生成字段 assert
。
这可以通过以下方式验证:
public class A {
public static void main(String[] args) {
assert false;
System.out.println(Arrays.toString(A.class.getDeclaredFields()));
}
}
设置所需的断言状态只需设置此字段(注意反转的布尔值):
// Helper method in any class
public static void setAssertionsEnabled(Class<?> clazz, boolean value)
throws ReflectiveOperationException
{
Field field = clazz.getDeclaredField("$assertionsDisabled");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(Test.class, !value);
}
最简单、最好的方法是:
public static void assertion(boolean condition, String conditionFailureMessage)
{
if(!condition)
throw new AssertionError(conditionFailureMessage);
}
无需将 -ea 设置为 VM 参数。
调用函数如下:
assertion(sum>=n,"sum cannot be less than n");
如果断言失败,代码将给出 AssertionError,否则代码将安全运行。
这个问题已经很老了,对于当今任何偶然发现这个问题的人来说,答案仍然是否定的,你无法在运行时可靠地启用断言。
但是您可以做的是实现以下内容并确保在运行时启用断言(如果您想强制执行):
private static void ensureAssertionsAreEnabled() {
try {
assert false;
} catch (AssertionError error) {
return;
}
throw new AssertionsNotEnabledError();
}
然后添加自定义错误类:
public class AssertionsNotEnabledError extends Error {
public AssertionsNotEnabledError() {
super("Assertions must be enabled for this application to function correctly. " +
"Please use the -ea flag as a VM argument when running the application.");
}
}
只记得调用ensureAssertionsAreEnabled();作为 Main.java 中的第一件事:
public class Main {
public static void main(String[] args) {
ensureAssertionsEnabled();
}
}
这是做什么的:
它尝试强制一个 AssertionError ,只有在启用断言时才会抛出该错误,因此,如果未启用断言,则不会抛出任何错误,并且忽略捕获,从而触发抛出 AssertionsNotEnabledError 。
但是,如果启用了断言,则会抛出 AssertionError 并且捕获将简单地返回,忽略下面的错误。