本文同步发表在 http://www.xeclipse.com/?p=1300
最近又抽空看了一下java的System类,发现了一些有意思的地方,做一个简单的整理吧,免得忘记了。
public final class System extends Object
System 类包含一些有用的类字段和方法。它不能被实例化。
在 System 类提供的设施中,有标准输入、标准输出和错误输出流;对外部定义的属性和环境变量的访问;加载文件和库的方法;还有快速复制数组的一部分的实用方法。
以上源自JDK 6.0的官方API说明,这里分享一下个人的理解。
这个类有几个比较重要的方法,比如
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
static long currentTimeMillis()
static Map<String,String> getenv()
static Properties getProperties()
static void loadLibrary(String libname)
static long nanoTime()
下面一一讲解一下:
计时
currentTimeMillis() 返回以毫秒为单位的当前时间。
nanoTime() 返回最准确的可用系统计时器的当前值,以毫微秒为单位。
这2个方法的区别很大,并非仅仅只是时间精度的区别。currentTimeMillis() 返回当前时间,而nanoTime() 只是返回一个毫微妙级别的数字,并非代表当前的系统时间。但是可以用返回的结果查进行经确定时。
long nanoTime1 = System.nanoTime();
long timeMillis1 = System.currentTimeMillis();
System.out.println("System.nanoTime():" + nanoTime1);
System.out.println("System.currentTimeMillis(): " + timeMillis1);
输出结果:
System.nanoTime():117701429470021
System.currentTimeMillis(): 1343123446809
并非只是差了10^6次方。
下面会讲到如何用nanoTime来进行准备计时。
数据复制
arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
这是一个很常用的方法,平时用到过,但是没怎么注意它的实现,结果上次就遇到一个小尴尬。按照一般来说,Java中的数组复制有2种情况,浅复制和深复制。前者就不必再赘述了,后者其实就是对元素的单独复制,2个数组之间不存在引用关系。
int size = 100000;
int[] sources = new int[size];
int[] destination = new int[size];
for (int index = 0; index < size; index++) {
destination[index] = sources[index];
}
long nanoTime2 = System.nanoTime();
long timeMillis2 = System.currentTimeMillis();
System.out.println("User array copy takes : " + (nanoTime2 - nanoTime1)
+ " in ns.");
System.out.println("User array copy takes : "
+ (timeMillis2 - timeMillis1) + " in ms");
System.arraycopy(sources, 0, destination, 0, size);
long nanoTime3 = System.nanoTime();
long timeMillis3 = System.currentTimeMillis();
System.out.println("System array copy takes : "
+ (nanoTime3 - nanoTime2) + " in ns.");
System.out.println("System array copy takes : "
+ (timeMillis3 - timeMillis2) + " in ms");
这里对100000个整型数组进行复制,分别采用数组复制和System的复制,看看结果:
User array copy takes : 2470705 in ns.
User array copy takes : 2 in ms
System array copy takes : 148977 in ns.
System array copy takes : 1 in ms
这里System的arrayCopy几乎要快一倍。
换几个值测试一下:
10000(1万)的情况
User array copy takes : 634974 in ns.
User array copy takes : 1 in ms
System array copy takes : 158578 in ns.
System array copy takes : 0 in ms
1000000(1百万)的情况
User array copy takes : 13381801 in ns.
User array copy takes : 13 in ms
System array copy takes : 1432499 in ns.
System array copy takes : 2 in ms
100000000(1千万)
User array copy takes : 72962115 in ns.
User array copy takes : 73 in ms
System array copy takes : 12106224 in ns.
System array copy takes : 12 in ms
对比一下知道了,System的arrayCopy要快很多。
为什么呢,看看方法的实现去:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
JNI实现,我觉得应该是使用了指针的移动进行计算的。不确定。。。
获取系统信息
getProperties() 确定当前的系统属性。
getenv() 返回一个不能修改的当前系统环境的字符串映射视图。
这里的2个方法都是获取系统信息的,一个是系统的一些属性信息,一个是系统环境变量。不过对于系统属性来说,Java提供了在当前JVM生命周期内临时修改的方法,
setProperty(String key, String value) 设置指定键指示的系统属性。
先看看getProperties():
java.version | Java 运行时环境版本 |
java.vendor | Java 运行时环境供应商 |
java.vendor.url | Java 供应商的 URL |
java.home | Java 安装目录 |
java.vm.specification.version | Java 虚拟机规范版本 |
java.vm.specification.vendor | Java 虚拟机规范供应商 |
java.vm.specification.name | Java 虚拟机规范名称 |
java.vm.version | Java 虚拟机实现版本 |
java.vm.vendor | Java 虚拟机实现供应商 |
java.vm.name | Java 虚拟机实现名称 |
java.specification.version | Java 运行时环境规范版本 |
java.specification.vendor | Java 运行时环境规范供应商 |
java.specification.name | Java 运行时环境规范名称 |
java.class.version | Java 类格式版本号 |
java.class.path | Java 类路径 |
java.library.path | 加载库时搜索的路径列表 |
java.io.tmpdir | 默认的临时文件路径 |
java.compiler | 要使用的 JIT 编译器的名称 |
java.ext.dirs | 一个或多个扩展目录的路径 |
os.name | 操作系统的名称 |
os.arch | 操作系统的架构 |
os.version | 操作系统的版本 |
file.separator | 文件分隔符(在 UNIX 系统中是“/”) |
path.separator | 路径分隔符(在 UNIX 系统中是“:”) |
line.separator | 行分隔符(在 UNIX 系统中是“/n”) |
user.name | 用户的账户名称 |
user.home | 用户的主目录 |
user.dir | 用户的当前工作目录 |
输出地结果为:写道
, java.vm.specification.vendor=Sun Microsystems Inc., user.variant=, os.name=Windows 7, sun.jnu.encoding=GBK, java.library.path=C:\Java\jdk1.6.0_17\bin;.;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;F:\IBM\WebSphere MQ\Java\lib;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Java\jdk1.6.0_17\bin;D:\Program Files\TortoiseSVN\bin;D:\library\apache-maven-3.0.3\bin;F:\IBM\WebSphere MQ\bin;F:\IBM\WebSphere MQ\tools\c\samples\bin;C:\Program Files\MySQL\MySQL Server 5.1\bin;D:\library\apache-ant-1.8.2/bin;C:\Program Files\Bitvise Tunnelier, java.specification.name=Java Platform API Specification, java.class.version=50.0, sun.management.compiler=HotSpot Client Compiler, os.version=6.1, user.home=C:\Users\LiXP, user.timezone=, java.awt.printerjob=sun.awt.windows.WPrinterJob, file.encoding=UTF-8, java.specification.version=1.6, java.class.path=E:\workspace\common_ws\org.salever.j2se.common\bin;E:\workspace\common_ws\org.salever.j2se.common\lib\activation.jar;E:\workspace\common_ws\org.salever.j2se.common\lib\commons-email-1.2.jar;E:\workspace\common_ws\org.salever.j2se.common\lib\mail.jar;E:\workspace\common_ws\org.salever.j2se.common\lib\jxl.jar;E:\workspace\common_ws\org.salever.j2se.common\lib\comm.jar;D:\Program Files\eclipse\plugins\org.junit_4.8.1.v4_8_1_v20100427-1100\junit.jar;D:\Program Files\eclipse\plugins\org.hamcrest.core_1.1.0.v20090501071000.jar;E:\workspace\common_ws\org.salever.j2se.common\lib\jacob.jar;E:\workspace\common_ws\org.salever.j2se.common\lib\commons-collections-3.2.1.jar;E:\workspace\common_ws\org.salever.j2se.common\lib\commons-lang-2.4.jar;E:\workspace\common_ws\org.salever.j2se.common\lib\velocity-1.6.4.jar, user.name=LiXP, java.vm.specification.version=1.0, java.home=C:\Java\jdk1.6.0_17\jre, sun.arch.data.model=32, user.language=en, java.specification.vendor=Sun Microsystems Inc., awt.toolkit=sun.awt.windows.WToolkit, java.vm.info=mixed mode, java.version=1.6.0_17, java.ext.dirs=C:\Java\jdk1.6.0_17\jre\lib\ext;C:\Windows\Sun\Java\lib\ext, sun.boot.class.path=C:\Java\jdk1.6.0_17\lib\tools.jar;C:\Java\jdk1.6.0_17\jre\lib\resources.jar;C:\Java\jdk1.6.0_17\jre\lib\rt.jar;C:\Java\jdk1.6.0_17\jre\lib\jsse.jar;C:\Java\jdk1.6.0_17\jre\lib\jce.jar;C:\Java\jdk1.6.0_17\jre\lib\charsets.jar, java.vendor=Sun Microsystems Inc., file.separator=\, java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi, sun.io.unicode.encoding=UnicodeLittle, sun.cpu.endian=little, sun.desktop=windows, sun.cpu.isalist=pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86}
这里还有一个实时设置属性的方法,其实在Java程序启动的时候,设置的参数-D也有这个功能。
先看看一个简单的使用:
System.setProperty("user.home", "c:/");
property = System.getProperty("user.home");
System.out.println("user.home:" + property);
property = System.getProperty("user.dir");
System.out.println("user.dir:" + property);
System.setProperty("user.dir", "c:/");
property = System.getProperty("user.dir");
System.out.println("user.dir:" + property);
property = System.getProperty("user.newArg");
System.out.println("user.newArg:" + property);
System.setProperty("user.newArg", "c:/");
property = System.getProperty("user.newArg");
System.out.println("user.newArg:" + property);
其中user.home user.dir都是已知属性,而user.newArg则是新创建的,看看打印的输出:
user.home:C:\Users\LiXP
user.home:c:/
user.dir:E:\workspace\common_ws\org.salever.j2se.common
user.dir:c:/
user.newArg:null
user.newArg:c:/
这里将user.home和user.dir都设置为c:/,然后在user.newArg被设置为新的值c:/
类似,如果在JVM启动参数加上:写道
打印的结果为:user.home:d:/
user.home:c:/
user.dir:d:/
user.dir:c:/
user.newArg:helloworld
user.newArg:c:/
关于-D开始的参数,参考上面得列表。
动态加载DLL类库
load(String filename) 从作为动态库的本地文件系统中以指定的文件名加载代码文件。
loadLibrary(String libname) 加载由 libname 参数指定的系统库。
这里主要用于JNI的使用,动态的加载DLL或者其他文件,关于JNI这里暂不讲述。只是提一下。System本身的很多方法都是通过JNI调用的本地方法,可想而知,JVM的实现必须要包含这些。