我正在使用 java swing 开发一个简单的应用程序,我想在 Windows、MacOS 和 Linux 中使用它。 当然,我正在尽力将其与操作系统集成。
对于 MacOS,我有这段代码,允许我在全局菜单中设置应用程序名称以及“关于”按钮的操作。
我使用以下代码:
if(System.getProperty("os.name").toUpperCase().startsWith("MAC")){
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "My app name");
System.setProperty("apple.awt.application.name", "My app name");
//Need for macos global menubar
System.setProperty("apple.laf.useScreenMenuBar", "true");
try{
com.apple.eawt.Application app = com.apple.eawt.Application.getApplication();
app.setDockIconImage(Toolkit.getDefaultToolkit().getImage(MainGUI.class.getResource("images/icon.png")));
app.setAboutHandler(new com.apple.eawt.AboutHandler() {
@Override
public void handleAbout(com.apple.eawt.AppEvent.AboutEvent aboutEvent) {
AboutDialog a = new AboutDialog();
a.setTitle("About");
a.pack();
a.setResizable(false);
centerDialogInScreen(a);
a.setVisible(true);
}
});
} catch (Throwable e){
//This means that the application is not being run on MAC OS.
//Just do nothing and go on...
}
}
当我在非 macos JAVA 上运行我的应用程序时,因为它的 JRE 没有 com.apple.eawt.* 类,JVM 应该抛出一个 NoDefClassFoundError,我正在捕获它并继续,对吗?
它似乎没有这样做,当我启动我的应用程序“.jar”时,我得到以下内容(在 Windows 上):
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/apple/eawt/AboutHandler
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
at java.lang.Class.privateGetMethodRecursive(Unknown Source)
at java.lang.Class.getMethod0(Unknown Source)
at java.lang.Class.getMethod(Unknown Source)
at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
Caused by: java.lang.ClassNotFoundException: com.apple.eawt.AboutHandler
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 7 more
我在这里缺少什么?
最佳答案
抛出 NoClassDefFoundError
的确切时间并不固定,但可能取决于 JVM 实现细节。就您而言,这是对类(class)的验证。在 HotSpot 中, validator 不会加载所有引用的类,但显然它尝试在您的情况下加载 AboutHandler
,这可能是由于您的类有一个实现 AboutHandler
的内部类造成的。 code> 和 Verifier 想要检查类型层次结构的一致性,即 AboutHandler
是否真的是一个接口(interface)。确切的细节并不那么重要,因为即使您设法解决它,结果也会很脆弱,并且可能会在其他版本或替代 JVM 实现中崩溃。
如果您想安全起见,则不得直接引用可能不存在的类。因此,您可以使用 Class.forName、Method.invoke 等以反射方式完成整个操作,但这会使任何重要的代码变得麻烦。更简单的解决方案是将整个 MacOS 特定代码放入其自己的类中,例如 MacSetup
。然后,您只需通过 Class.forName
加载此类(仅在检查您正在 MacOS 上运行之后)即可将其分离。
public class MacSetup implements Runnable {
@Override
public void run() {
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "My app name");
System.setProperty("apple.awt.application.name", "My app name");
//Need for macos global menubar
System.setProperty("apple.laf.useScreenMenuBar", "true");
com.apple.eawt.Application app = com.apple.eawt.Application.getApplication();
app.setDockIconImage(Toolkit.getDefaultToolkit().getImage(MainGUI.class.getResource("images/icon.png")));
app.setAboutHandler(new com.apple.eawt.AboutHandler() {
@Override
public void handleAbout(com.apple.eawt.AppEvent.AboutEvent aboutEvent) {
AboutDialog a = new AboutDialog();
a.setTitle("About");
a.pack();
a.setResizable(false);
centerDialogInScreen(a);
a.setVisible(true);
}
});
}
}
主类:
if(System.getProperty("os.name").toUpperCase().startsWith("MAC")) {
try {
Class.forName("MacSetup").asSubclass(Runnable.class).newInstance().run();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
// since this code is only executed when we *are* on MacOS, we should report it
Logger.getLogger("MacSetup").log(Level.SEVERE, null, ex);
}
}
因此,主类与 MacSetup
类及其所有引用分离,因为它以反射方式加载该类,并通过始终存在的 Runnable
调用其实现方法接口(interface),将反射操作减少到必要的最低限度。
关于java - 在非 MACOS JRE 上捕获 java.lang.NoClassDefFoundError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42818440/