我正在研究的项目是一个支持两个不同平台的API。在运行时,类路径中实际上只有两个平台之一。
在大多数情况下,我很容易就能编写出像这样的代码
#include "fenprinc.h"
fenPrinc::fenPrinc()
{
QWidget *zoneC= new QWidget;
setCentralWidget(zoneC);
}
即使if(isPlatformOne(){
PlatformOne.doSomething();
}
在运行时不存在,事先进行的检查也意味着代码不会运行,并且不会引发任何错误。这项技术适用于大多数情况下的VAST,但是有一种情况我遇到了抛出错误的情况。
如果PlatformOne
还实现了一个不存在的接口,并且该接口与不存在ALSO的参数一起使用,则在装入包含类时立即抛出PlatformOne
,无论代码是否实际执行与否。
以下是一个示例:
接口:
NoClassDefFoundError
班级:
public interface DeleteInterface {
void test(DeleteInterface delete);
}
主要:
public class DeleteClass implements DeleteInterface {
@Override
public void test(DeleteInterface delete) {
}
}
从jar中删除public class Test {
private final boolean test; //Cannot be constant or compiler will erase unreachable code
public Test() {
test = false;
}
public static void main(String[] args) {
if (new Test().test) {
DeleteClass c = new DeleteClass();
c.test(c);
}
System.out.println("SUCCESS!");
}
}
和DeleteClass
会在运行时产生以下错误:
DeleteInterface
为什么仅在这种特定情况下会引发错误?在不访问任何目标平台代码的情况下解决该错误的最佳方法是什么?
答案 0 :(得分:1)
由于额外的验证,Java验证程序甚至可能在完全加载类之前就抛出NoClassDefFoundError
,例如必须存在方法返回类型,此外,您正在Main类中执行此操作,JRE会在启动时对其进行扫描,如您所见在堆栈跟踪中。
将不需要代码的代码移至其他类,然后将其移至要使用的位置,首先检查该类是否存在,然后从该额外的类中调用方法:
class MyExtraClass {
public static void doStuff() {
DeleteClass c = new DeleteClass();
c.test(c);
}
}
public boolean checkForClass(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) { return false; }
}
// somewhere in your code
if (checkForClass("package.DeletedClass")) {
MyExtraClass.doStuff();
}
在这种情况下,这是最安全的选择,如果代码很短,您也可以使用一些本地类:(但在大多数情况下效果并不理想)
// somewhere in your code
if (checkForClass("package.DeletedClass")) {
new Runnable() {
@Override public void run() {
DeleteClass c = new DeleteClass();
c.test(c);
}.run();
}
}
答案 1 :(得分:0)
实际上我今天有这个问题。
确保不要在系统类加载器中两次加载同一类。
I.E)我在前端线程中引用了a.b.class,并且试图引用具有相同路径和类名称的库方法,因此对我抛出了相同的错误。
我将代理程序引用中的名称更改为与前端引用不同,并且错误停止了。
希望这会有所帮助
答案 2 :(得分:0)
从罐子中删除DeleteClass和DeleteInterface会产生 运行时出现以下错误:
如果所需的类在运行时不存在,请确定,将抛出java.lang.NoClassDefFoundError
。
即使PlatformOne在运行时不存在,也要事先进行检查 表示代码无法运行,也不会引发任何错误。
请检查您的代码是否消化了所引发的错误,如果是,则您的应用不会崩溃,并且可以正常执行。例如。下面的代码段将抛出NoClassDefFoundError
,但不会崩溃,因为您可以消化该错误。
public bool isPlatformOne() {
try {
...
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
如果您的用例只是检查特定的类是否存在,则可以使用Class.forName
来检查该类的存在。例如。
// className is the fully qualified class name.
public boolean hasClass(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
在代码中使用它的示例。
if (hasClass("android.support.v7.app.AppCompatActivity")) {
...
}