Как уже говорили другие, в Java не существует такой вещи, как # define / # ifdef. Но что касается вашей проблемы наличия дополнительных внешних библиотек, которые вы бы использовали, если они есть, и не использовали бы, если бы не использовали, использование прокси-классов может быть вариантом (если интерфейсы библиотек не слишком велики).
Мне пришлось сделать это один раз для конкретных расширений Mac OS X для AWT / Swing (находится в 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
}
Все это имеет смысл, только если вам нужно всего несколько классов из внешней библиотеки, потому что вы должны делать все с помощью отражения во время выполнения. Для больших библиотек вам, вероятно, понадобится какой-то способ автоматизации генерации прокси. Но затем, если вы действительно зависите от большой внешней библиотеки, вам просто нужно это сделать во время компиляции.
Комментарий Питера Лоури: (Извините, что отредактировал, очень сложно вставить код в комментарий)
Следующий пример является общим для метода, поэтому вам не нужно знать все используемые методы. Вы также можете сделать это универсальным для каждого класса, поэтому вам нужен только один класс 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);
}