Java Mac OS X特定操作会使应用程序在其他操作系统上崩溃';s尽管先检查了操作系统
我使用以下代码将Java应用程序与Mac OS X集成:Java Mac OS X特定操作会使应用程序在其他操作系统上崩溃';s尽管先检查了操作系统,java,cross-platform,Java,Cross Platform,我使用以下代码将Java应用程序与Mac OS X集成: if (System.getProperty("os.name").equals("Mac OS X")) { System.setProperty("com.apple.mrj.application.apple.menu.about.name", "JoText"); // Program name com.apple.eawt.Application.getApplication().setDockIconImage
if (System.getProperty("os.name").equals("Mac OS X"))
{
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "JoText"); // Program name
com.apple.eawt.Application.getApplication().setDockIconImage(new javax.swing.ImageIcon( JotextMain.class.getResource("icons/Icon.png") ).getImage()); // Dock icon
System.setProperty("apple.laf.useScreenMenuBar", "true"); // Use global menu bar
com.apple.eawt.Application.getApplication().addApplicationListener(new MacAboutAndQuit()); //Make "Quit" and "About" options work
}
在MacOSX上,它运行良好。但在Ubuntu上:
Exception in thread "main" java.lang.NoClassDefFoundError: com/apple/eawt/ApplicationListener
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2451)
at java.lang.Class.getMethod0(Class.java:2694)
at java.lang.Class.getMethod(Class.java:1622)
at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:494)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:486)
Caused by: java.lang.ClassNotFoundException: com.apple.eawt.ApplicationListener
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 6 more
当我注释掉这些代码时,它在Ubuntu上启动得很好。
奇怪,因为它在执行MacOSX特定操作之前先检查MacOSX。
我没有Windows,但我的一个使用Windows的朋友也报告了我的.jar没有启动,而是从Java虚拟机启动器发出了一条“发生了Java异常”的消息。在学校的Windows PC上,同样的问题
这是什么原因造成的?如果问题出在
块的第二行(以及第四行)。即使您的代码从未调用过该函数,JVM仍然必须尝试在初始化包含该if
语句的任何类时加载com.apple.eawt.Application
类,这仅仅是因为对它的引用。当您不在Mac上时,该类不存在,因此会出现错误
一种解决方法是使用反射进行函数调用。这将防止类装入器在实际调用之前尝试装入该类
示例
javax.swing.ImageIcon icon = ...
Class c = Class.forName("com.apple.eawt.Application");
Method m = c.getMethod("getApplication");
Object applicationInstance = m.invoke(null);
m = applicationInstance.getClass().getMethod("setDockIconImage", javax.swing.ImageIcon.class);
m.invoke(applicationInstance,icon);
这是if
块中第二行的反射等价物。这与良好的开发实践背道而驰——如果类/方法名称发生更改,您将不会收到编译器警告,但它确实允许您对特定类型进行调用,而无需在源代码中直接引用它们。这将防止类加载器加载那些特定于操作系统的类,直到您实际进入if
语句
为了稍微清理一下,您可以创建一个特殊的类来处理所有Mac OS特定的东西,将该功能封装在一个方法中,然后像下面的示例那样使用反射调用该方法-这将为您节省一个method m=…
-样式的调用
反射警告
除了这段代码丑陋且不易维护之外,反射速度非常慢。最好在这样的情况下使用它,在程序运行期间,您可能要初始化某个东西一次。通常,如果不是因为可维护性问题,出于性能原因,您希望远离反射
有关反射性能的更多信息,请阅读此内容:
更优雅的解决方案
与其用反射代码替换if
块中的所有内容,我将创建一个接口,如下所示:
interface SpecificPlatform{
void initialize(javax.swing.ImageIcon icon);
}
然后,我将为Mac实现它:
class MacOSX implements SpecificPlatform{
@Override
public void initialize(javax.swing.ImageIcon icon){
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "JoText");
Application.getApplication().setDockIconImage(new javax.swing.ImageIcon(
JotextMain.class.getResource("icons/Icon.png") ).getImage()); // Dock icon
System.setProperty("apple.laf.useScreenMenuBar", "true"); // Use global menu bar
Application.getApplication().addApplicationListener(new MacAboutAndQuit());
}
}
现在。。。将原始代码更改为以下内容:
javax.swing.ImageIcon icon = ...
SpecificPlatform sp = null;
if (System.getProperty("os.name").equals("Mac OS X"))
sp = (SpecificPlatform)(Class.forName("pkg.name.MacOSX").getConstructor().
newInstance());
}
//Check for other OS-specific classes here ...
if(sp != null) sp.initialize(icon);
现在,每个操作系统只有一个丑陋的反射调用,而不是对每个操作系统特定的方法调用都进行一大堆丑陋的反射调用。if
块的第二行(以及第四行)是问题所在。即使您的代码从未调用过该函数,JVM仍然必须尝试在初始化包含该if
语句的任何类时加载com.apple.eawt.Application
类,这仅仅是因为对它的引用。当您不在Mac上时,该类不存在,因此会出现错误
一种解决方法是使用反射进行函数调用。这将防止类装入器在实际调用之前尝试装入该类
示例
javax.swing.ImageIcon icon = ...
Class c = Class.forName("com.apple.eawt.Application");
Method m = c.getMethod("getApplication");
Object applicationInstance = m.invoke(null);
m = applicationInstance.getClass().getMethod("setDockIconImage", javax.swing.ImageIcon.class);
m.invoke(applicationInstance,icon);
这是if
块中第二行的反射等价物。这与良好的开发实践背道而驰——如果类/方法名称发生更改,您将不会收到编译器警告,但它确实允许您对特定类型进行调用,而无需在源代码中直接引用它们。这将防止类加载器加载那些特定于操作系统的类,直到您实际进入if
语句
为了稍微清理一下,您可以创建一个特殊的类来处理所有Mac OS特定的东西,将该功能封装在一个方法中,然后像下面的示例那样使用反射调用该方法-这将为您节省一个method m=…
-样式的调用
反射警告
除了这段代码丑陋且不易维护之外,反射速度非常慢。最好在这样的情况下使用它,在程序运行期间,您可能要初始化某个东西一次。通常,如果不是因为可维护性问题,出于性能原因,您希望远离反射
有关反射性能的更多信息,请阅读此内容:
更优雅的解决方案
与其用反射代码替换if
块中的所有内容,我将创建一个接口,如下所示:
interface SpecificPlatform{
void initialize(javax.swing.ImageIcon icon);
}
然后,我将为Mac实现它:
class MacOSX implements SpecificPlatform{
@Override
public void initialize(javax.swing.ImageIcon icon){
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "JoText");
Application.getApplication().setDockIconImage(new javax.swing.ImageIcon(
JotextMain.class.getResource("icons/Icon.png") ).getImage()); // Dock icon
System.setProperty("apple.laf.useScreenMenuBar", "true"); // Use global menu bar
Application.getApplication().addApplicationListener(new MacAboutAndQuit());
}
}
现在。。。将原始代码更改为以下内容:
javax.swing.ImageIcon icon = ...
SpecificPlatform sp = null;
if (System.getProperty("os.name").equals("Mac OS X"))
sp = (SpecificPlatform)(Class.forName("pkg.name.MacOSX").getConstructor().
newInstance());
}
//Check for other OS-specific classes here ...
if(sp != null) sp.initialize(icon);
现在,每个操作系统只有一个丑陋的反射调用,而不是对每个操作系统特定的方法调用进行一大堆丑陋的反射调用。您确定代码中没有尾随括号或花括号(您可能没有复制到这里?)。在我看来,你的代码应该能正常工作。您还可以打印出
System.getProperty(“os.name”)
的结果。。。在您的原始代码中,它看起来确实像是一个非常愚蠢的打字错误或错误。您确定代码中的某个地方没有尾随括号或花括号(您可能没有复制到这里?)。在我看来,你的代码应该能正常工作。您还可以打印出System.getProperty(“os.name”)
的结果。。。在您的原始代码中,它看起来确实是一个愚蠢的打字错误或错误。您能提供一个使用反射的例子吗?我试过了