java.lang.System类浅析

本文同步发表在 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.versionJava 运行时环境版本
java.vendorJava 运行时环境供应商
java.vendor.urlJava 供应商的 URL
java.homeJava 安装目录
java.vm.specification.versionJava 虚拟机规范版本
java.vm.specification.vendorJava 虚拟机规范供应商
java.vm.specification.nameJava 虚拟机规范名称
java.vm.versionJava 虚拟机实现版本
java.vm.vendorJava 虚拟机实现供应商
java.vm.nameJava 虚拟机实现名称
java.specification.versionJava 运行时环境规范版本
java.specification.vendorJava 运行时环境规范供应商
java.specification.nameJava 运行时环境规范名称
java.class.versionJava 类格式版本号
java.class.pathJava 类路径
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.runtime.name=Java(TM) SE Runtime Environment, sun.boot.library.path=C:\Java\jdk1.6.0_17\jre\bin, java.vm.version=14.3-b01, java.vm.vendor=Sun Microsystems Inc., java.vendor.url=http://java.sun.com/, path.separator=;, java.vm.name=Java HotSpot(TM) Client VM, file.encoding.pkg=sun.io, sun.java.launcher=SUN_STANDARD, user.country=US, sun.os.patch.level=, java.vm.specification.name=Java Virtual Machine Specification, user.dir=E:\workspace\common_ws\org.salever.j2se.common, java.runtime.version=1.6.0_17-b04, java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment, java.endorsed.dirs=C:\Java\jdk1.6.0_17\jre\lib\endorsed, os.arch=x86, java.io.tmpdir=C:\Users\LiXP\TEMP\, line.separator=
, 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启动参数加上:写道

-Duser.home=d:/ -Duser.dir=d:/ -Duser.newArg=helloworld
 

打印的结果为: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的实现必须要包含这些。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值