У меня возникла такая же потребность, поскольку у нас есть код, который должен запускаться на всех версиях Java из Java 1.2, но некоторый код должен использовать преимущества более новых API, если они доступны.
После различных перестановок, использующих отражение для получения объектов Метода и их динамического вызова, я в общем остановился на подходе стиля обертки (хотя в некоторых случаях лучше просто сохранить отраженный метод как статический и вызвать его лучше - это зависит).
Ниже приведен пример класса «System Utility», который предоставляет некоторые более новые API. В этом примере используется Singleton, но он может легко создать несколько объектов, если это требуется базовому API.
Есть два класса:
Последний используется, если JVM во время выполнения - Java 5 или новее. В противном случае резервные методы, которые совместимы в контракте, используются из реализации по умолчанию в SysUtil, которая использует только Java 4 или более ранние API. Каждый класс компилируется с помощью компилятора конкретной версии, поэтому случайное использование API Java 5+ в классе Java 4 невозможно:
SysUtil (скомпилировано с компилятором Java 4)
<code>import java.io.*;
import java.util.*;
/**
* Masks direct use of select system methods to allow transparent use of facilities only
* available in Java 5+ JVM.
*
* Threading Design : [ ] Single Threaded [x] Threadsafe [ ] Immutable [ ] Isolated
*/
public class SysUtil
extends Object
{
/** Package protected to allow subclass SysUtil_J5 to invoke it. */
SysUtil() {
super();
}
// *****************************************************************************
// INSTANCE METHODS - SUBCLASS OVERRIDE REQUIRED
// *****************************************************************************
/** Package protected to allow subclass SysUtil_J5 to override it. */
int availableProcessors() {
return 1;
}
/** Package protected to allow subclass SysUtil_J5 to override it. */
long milliTime() {
return System.currentTimeMillis();
}
/** Package protected to allow subclass SysUtil_J5 to override it. */
long nanoTime() {
return (System.currentTimeMillis()*1000000L);
}
// *****************************************************************************
// STATIC PROPERTIES
// *****************************************************************************
static private final SysUtil INSTANCE;
static {
SysUtil instance=null;
try { instance=(SysUtil)Class.forName("SysUtil_J5").newInstance(); } // can't use new SysUtil_J5() - compiler reports "class file has wrong version 49.0, should be 47.0"
catch(Throwable thr) { instance=new SysUtil(); }
INSTANCE=instance;
}
// *****************************************************************************
// STATIC METHODS
// *****************************************************************************
/**
* Returns the number of processors available to the Java virtual machine.
* <p>
* This value may change during a particular invocation of the virtual machine. Applications that are sensitive to the
* number of available processors should therefore occasionally poll this property and adjust their resource usage
* appropriately.
*/
static public int getAvailableProcessors() {
return INSTANCE.availableProcessors();
}
/**
* Returns the current time in milliseconds.
* <p>
* Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the
* underlying operating system and may be larger. For example, many operating systems measure time in units of tens of
* milliseconds.
* <p>
* See the description of the class Date for a discussion of slight discrepancies that may arise between "computer time"
* and coordinated universal time (UTC).
* <p>
* @return The difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
*/
static public long getMilliTime() {
return INSTANCE.milliTime();
}
/**
* Returns the current value of the most precise available system timer, in nanoseconds.
* <p>
* This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock
* time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values
* may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees
* are made about how frequently values change. Differences in successive calls that span greater than approximately 292
* years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.
* <p>
* For example, to measure how long some code takes to execute:
* <p><pre>
* long startTime = SysUtil.getNanoTime();
* // ... the code being measured ...
* long estimatedTime = SysUtil.getNanoTime() - startTime;
*
*
* @return Текущее значение системного таймера в наносекундах.
* /
static public long getNanoTime () {
return INSTANCE.nanoTime ();
}
} // КОНЕЦ ОБЩЕСТВЕННОГО КЛАССА
SysUtil_J5 (скомпилировано с компилятором Java 5)
import java.util.*;
class SysUtil_J5
extends SysUtil
{
private final Runtime runtime;
SysUtil_J5() {
super();
runtime=Runtime.getRuntime();
}
// *****************************************************************************
// INSTANCE METHODS
// *****************************************************************************
int availableProcessors() {
return runtime.availableProcessors();
}
long milliTime() {
return System.currentTimeMillis();
}
long nanoTime() {
return System.nanoTime();
}
} // END PUBLIC CLASS