自 1.1 以来,我一直需要在 JSE 中支持每一个 JVM,并使用这些包装技术来兼容支持可选的 API——也就是说,使应用程序更好地工作的 API,但对它来说不是必需的。
我使用的两种技术似乎(很差?)在您引用的文章中进行了描述。与其进一步评论,我将提供我如何做到这一点的真实例子。
最简单 - 静态包装方法
需要:如果 API 可用则调用它,否则什么也不做。这可以针对任何 JVM 版本进行编译。
首先,设置一个Method
具有反射方法的静态,如下所示:
static private final java.lang.reflect.Method SET_ACCELERATION_PRIORITY;
static {
java.lang.reflect.Method mth=null;
try { mth=java.awt.Image.class.getMethod("setAccelerationPriority",new Class[]{Float.TYPE}); } catch(Throwable thr) { mth=null; }
SET_ACCELERATION_PRIORITY=mth;
}
并包装反射方法而不是使用直接调用:
static public void setImageAcceleration(Image img, int accpty) {
if(accpty>0 && SET_ACCELERATION_PRIORITY!=null) {
try { SET_ACCELERATION_PRIORITY.invoke(img,new Object[]{new Float(accpty)}); }
catch(Throwable thr) { throw new RuntimeException(thr); } // exception will never happen, but don't swallow - that's bad practice
}
}
更难 - 静态包装类
需要:调用可用的 API,或者调用旧的 API 以获得等效但降级的功能。这必须针对较新的 JVM 版本进行编译。
首先建立一个静态包装类;这可能是一个静态单例包装器,或者您可能需要包装每个实例创建。以下示例使用静态单例:
package xxx;
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();
}
/** 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 milliTick() {
return System.currentTimeMillis();
}
/** Package protected to allow subclass SysUtil_J5 to override it. */
long nanoTick() {
return (System.currentTimeMillis()*1000000L);
}
// *****************************************************************************
// STATIC PROPERTIES
// *****************************************************************************
static private final SysUtil INSTANCE;
static {
SysUtil instance=null;
try { instance=(SysUtil)Class.forName("xxx.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 value of the most precise available system timer, in milliseconds.
* <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 milliseconds since some fixed but arbitrary time (perhaps in the future, so
* values may be negative). This method provides millisecond precision, but not necessarily millisecond accuracy. No
* guarantees are made about how frequently values change. Differences in successive calls that span greater than
* approximately 292,000 years 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.getNanoTick();
* // ... the code being measured ...
* long estimatedTime = SysUtil.getNanoTick() - startTime;
* </pre>
* <p>
* @return The current value of the system timer, in milliseconds.
*/
static public long getMilliTick() {
return INSTANCE.milliTick();
}
/**
* 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 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.getNanoTick();
* // ... the code being measured ...
* long estimatedTime = SysUtil.getNanoTick() - startTime;
* </pre>
* <p>
* @return The current value of the system timer, in nanoseconds.
*/
static public long getNanoTick() {
return INSTANCE.nanoTick();
}
} // END PUBLIC CLASS
并创建一个子类以在可用时提供更新的功能:
package xxx;
import java.util.*;
class SysUtil_J5
extends SysUtil
{
private final Runtime runtime;
SysUtil_J5() {
super();
runtime=Runtime.getRuntime();
}
int availableProcessors() {
return runtime.availableProcessors();
}
long milliTick() {
return (System.nanoTime()/1000000);
}
long nanoTick() {
return System.nanoTime();
}
} // END PUBLIC CLASS