简体   繁体   中英

Dynamically loading class during runtime

I'm developing a Java application for both Windows and Mac OSX. There are some platform-dependent pieces of code. Rather than splitting the source code into two separate branches, the application will establish the platform during runtime and then execute the proper code.

This has worked like a charm. But I'm now using the following code which should only be executed on computers running Mac OSX:

package abc.extension;

import com.apple.eawt.Application;
import abc.Globals;

public class osx {
    public static void setApplicationLook() {
        Application application = Application.getApplication();
        application.setDockIconImage(Globals.iconImage);
    }
}

The above code works perfectly fine. But as it imports a class that is only available on Mac OSX, the application will not compile or run on other platforms.

I believe the solution would be to dynamically import com.apple.eawt.Application in the function setApplicationLook() . As that function will only be called on computers running Mac OSX, this will not raise any errors on other platforms.

But how would one go about doing this?

You can either;

  • make sure every class which you need to compile is available when you compile the program, regardless of the platform you are on or
  • use the reflection library to call the method so it doesn't need to be available at compile time.

Using reflections instead you can do

// import com.apple.eawt.Application;
Class applicationClass = Class.forName("com.apple.eawt.Application"):

// Application application = Application.getApplication();
Object application = applicationClass.getMethod("getApplication()")
                                     .invoke(null); // static method.

// application.setDockIconImage(Globals.iconImage);
appplicationClass.getMethod("setDockIconImage", Image.class)
                 .invoke(application, Globals.iconImage);

If you want to avoid reflection, class loading behavior is defined in the specs :

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.

...

A class or interface will not be initialized under any other circumstance.

As long as you have the Mac libraries (maybe even a stub) at compile time, you do not need to worry if you have them at runtime unless you execute a method in a class that uses them.

Took me a while trying combinations of getMethod and random code, but I got there.

public static void setApplicationLook() {
    Class aClass = classLoader.loadClass("com.apple.eawt.Application");
    Method getApplication = aClass.getMethod("getApplication", null);
    Object application = getApplication.invoke(null);
    Method setDockIconImage = aClass.getMethod("setDockIconImage", Image.class);
    setDockIconImage.invoke(application, Globals.iconImage);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM