5

我有一个编译的可执行 JAR 文件在 Windows 平台上失败。

这样做的原因是因为我想正确集成某些特定于 OS X 的属性——例如About window

即使我使用条件特别封锁了代码,JAR 仍然在NoClassDefFoundError执行的第一行就崩溃了。

if (isOSX()) {
    com.apple.eawt.Application application = com.apple.eawt.Application.getApplication();
    application.setAboutHandler(new com.apple.eawt.AboutHandler() {
        @Override
        public void handleAbout(com.apple.eawt.AppEvent.AboutEvent ae) {
            new AboutWindow();
        }
    });
    application.setDefaultMenuBar(MenuSystem.createMenu());
}

是否可以将此代码包含在我的 JAR 文件中,以便我可以拥有一个一致的代码库?

4

3 回答 3

9

布赖恩的回答为基础,我能够使用以下代码使用 OS X 特定方法设置 Mac 停靠图标图像。与其他答案不同,此答案包含一个完整的示例,并且没有尝试将对象强制转换为 OS X 特定类对象的问题。

代码的作用:

  1. 此代码不是导入 OS X 特定库,而是Class.forName(String)用于获取Class与 OS X 特定类关联的对象。在此示例中,该com.apple.eawt.Application库用于设置停靠图标图像。
  2. 然后使用反射来调用 OS X 特定类的方法。getClass()用于获取Application对象,getMethod().invoke()用于调用getApplication()setDockIconImage()方法。

我已经包含了显示通常在 OS X 专有程序中使用的代码的注释,以明确反射代码正在替换什么。(如果您正在创建一个只需要在 Mac 上运行的程序,请参阅如何更改 Java 程序的 Dock 图标?了解设置停靠图标图像所需的代码。)

// Retrieve the Image object from the locally stored image file
// "frame" is the name of my JFrame variable, and "filename" is the name of the image file
Image image = Toolkit.getDefaultToolkit().getImage(frame.getClass().getResource(fileName));

try {
    // Replace: import com.apple.eawt.Application
    String className = "com.apple.eawt.Application";
    Class<?> cls = Class.forName(className);

    // Replace: Application application = Application.getApplication();
    Object application = cls.newInstance().getClass().getMethod("getApplication")
        .invoke(null);

    // Replace: application.setDockIconImage(image);
    application.getClass().getMethod("setDockIconImage", java.awt.Image.class)
        .invoke(application, image);
}
catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException
        | InvocationTargetException | NoSuchMethodException | SecurityException
        | InstantiationException e) {
    e.printStackTrace();
}

Although this code works, this method still seems to be a messy workaround, and it would be great if anyone has any other suggestions on how to include OS X specific code in a program used on Mac and Windows.

于 2017-05-09T15:18:39.700 回答
5

您是否尝试过使用Class.forName动态加载周围的类?

Class.forName("com.myproject.ClassContainingApple");

这样,您可以在一个类中引用所有 Apple 特定的类,并将其动态加载到您的isOSX()分支中。您必须这样做,因为您无法加载引用其他不可用类的类 - 您必须确定您是否在 OSX 中,然后加载引用仅 OSX 类的任何内容。

如果您有更多特定于操作系统的要求,一种可扩展的方法是在操作系统之后命名您的类,然后根据检测到的操作系统加载类名。例如调用你的类WindowsExtensionsOSXExtensions等等LinuxExtensions(你必须查找适当的名称 - 我只是提供示例)

例如,这是一个使用示例:

String className = ""java.util.ArrayList";
Class cls = Class.forName(className);
List list = (List)cls.newInstance();
于 2012-11-15T15:40:35.663 回答
0

这是不可能的,因为 java 正在加载一个类(可能)在类的实例化期间使用的所有类,因此命名的类不可用。

您可以尝试将代码放在项目中的另一个类中,并且仅当您在 OSX 上运行时才实例化此类。

如果这不起作用,您必须使用反射,因为当您通过反射加载它时,VM 只能检测到此类。

高温高压

于 2012-11-15T15:44:58.743 回答