正如其他人所说,Java 中没有#define/#ifdef 这样的东西。但是关于您拥有可选外部库的问题,如果存在,您将使用,如果没有,则不使用,使用代理类可能是一种选择(如果库接口不是太大)。
我必须为 AWT/Swing 的 Mac OS X 特定扩展(在 com.apple.eawt.* 中找到)执行此操作。当然,如果应用程序在 Mac OS 上运行,这些类仅在类路径上。为了能够使用它们但仍然允许在其他平台上使用相同的应用程序,我编写了简单的代理类,它提供了与原始 EAWT 类相同的方法。在内部,代理使用一些反射来确定真正的类是否在类路径上,并且会通过所有方法调用。通过使用java.lang.reflect.Proxy 类,您甚至可以创建和传递外部库中定义的类型的对象,而无需在编译时使用它。
例如,com.apple.eawt.ApplicationListener 的代理如下所示:
public class ApplicationListener {
private static Class<?> nativeClass;
static Class<?> getNativeClass() {
try {
if (ApplicationListener.nativeClass == null) {
ApplicationListener.nativeClass = Class.forName("com.apple.eawt.ApplicationListener");
}
return ApplicationListener.nativeClass;
} catch (ClassNotFoundException ex) {
throw new RuntimeException("This system does not support the Apple EAWT!", ex);
}
}
private Object nativeObject;
public ApplicationListener() {
Class<?> nativeClass = ApplicationListener.getNativeClass();
this.nativeObject = Proxy.newProxyInstance(nativeClass.getClassLoader(), new Class<?>[] {
nativeClass
}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
ApplicationEvent event = new ApplicationEvent(args[0]);
if (methodName.equals("handleReOpenApplication")) {
ApplicationListener.this.handleReOpenApplication(event);
} else if (methodName.equals("handleQuit")) {
ApplicationListener.this.handleQuit(event);
} else if (methodName.equals("handlePrintFile")) {
ApplicationListener.this.handlePrintFile(event);
} else if (methodName.equals("handlePreferences")) {
ApplicationListener.this.handlePreferences(event);
} else if (methodName.equals("handleOpenFile")) {
ApplicationListener.this.handleOpenFile(event);
} else if (methodName.equals("handleOpenApplication")) {
ApplicationListener.this.handleOpenApplication(event);
} else if (methodName.equals("handleAbout")) {
ApplicationListener.this.handleAbout(event);
}
return null;
}
});
}
Object getNativeObject() {
return this.nativeObject;
}
// followed by abstract definitions of all handle...(ApplicationEvent) methods
}
如果您只需要来自外部库的几个类,那么所有这些都是有意义的,因为您必须在运行时通过反射来完成所有事情。对于较大的库,您可能需要一些方法来自动生成代理。但是,如果你真的那么依赖一个大型的外部库,你应该在编译时才需要它。
Peter Lawrey 的评论:(抱歉编辑,很难将代码放入评论中)
以下示例是按方法通用的,因此您无需了解所有涉及的方法。您也可以按类进行通用化,这样您只需要一个 InvocationHandler 类来编码即可涵盖所有情况。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
ApplicationEvent event = new ApplicationEvent(args[0]);
Method method = ApplicationListener.class.getMethod(methodName, ApplicationEvent.class);
return method.invoke(ApplicationListener.this, event);
}