Java程序在不同操作系统上运行时,可能需要取得平台相关的属性,或者调用平台命令来完成特点功能。Java提供了System类和Runtime类来与程序的运行平台进行交互。
本文讲述System类,需要了解Runtime类的,前往:【小家java】聊聊Java中的Runtime类
主要API
System类提供了代表标准输入、标准输出和错误输出的类变量,并提供一些静态方法用于访问环境变量、系统属性的方法,还提供了加载文件和动态链接库的方法。
我们看看我们偶尔会用到的关于GC的方法:
public static void exit(int status) { Runtime.getRuntime().exit(status); } public static void gc() { Runtime.getRuntime().gc(); }
还有load、loadLibrary、runFinalization、runFinalizersOnExit等方法,无一例外底层都是调用Runtime类的方法,所以此处不再鳌诉了。
获取环境变量和属性值的方法
一个例子,说明一切:
public static void main(String[] args) { //系统环境变量 (注意不是JVM的参数哦) 比如配置的JAVA_HOME等等值 Map<String, String> envMap = System.getenv(); //获取JVM的启动参数们: //比如托是通过如下方式启动:通过java -jar test.jar -Denv=123启动时指定的值 Properties properties = System.getProperties(); //获取所有的参数 System.out.println(properties.getProperty("env")); //123 //启动参数:的获取(用得很少 注意和上面的区别) //比如启动方式为 java -jar test.jar --env=123 这该参数就在main方法的args里 System.out.println(args); }
备注:我发现getenv这个方法没有遵循驼峰命名规范,怪别扭的。
比如JDK中的Hashtable类,也是一个命名不规范的例子。
下面这些属性值,都可以通过System.getProperty("")来获取
获取系统当前时间方法
currentTimeMillis()和nanoTime()
其实大家都用得非常的多了,获取当前时间特别有效。特别是currentTimeMillis。
public static void main(String[] args) { System.out.println(System.currentTimeMillis()); System.out.println(System.nanoTime()); //1534776548329 //45386393379944 }
我们发现他俩的值只相差了一位数。所以一定要注意nanoTime返回的并不是纳秒,并不是纳秒,并不是纳秒。其实它的单位叫毫微秒,只是更加的精准些。所以JDK上有说:
System.nanoTime提供相对精确的计时,但是不能用他来计算当前日期。此方法提供毫微秒的精度,但不是必要的毫微秒的准确度。它对于值的更改频率没有作出保证。
所以我们可以用它了计算差值,但千万不要拿来作为时间。它是JDK1.5才提供的
System.currentTimeMillis返回的是从1970.1.1 UTC 零点开始到现在的时间,精确到毫秒,平时我们可以根据System.currentTimeMillis来计算当前日期,星期几等,可以方便的与Date进行转换
标准输入、输出方法
System类的in、out、err分别代表系统的标准输入(通常是键盘)、标准输出(通常是显示器)和错误输出流,并提供了setIn()、setOut()、setErr()方法来改变系统的标准输入、标准输出和标准错误输出流
setOut()方法可以改变输出流
public static void main(String[] args) throws Exception { PrintStream out = System.out; //先把标准的输出缓存到变量 PrintStream ps = new PrintStream("log.txt"); System.setOut(ps); int age = 11; System.out.println("年龄变量成功定义,初始值为11"); String sex = "女"; System.out.println("年龄变量成功定义,初始值为女"); //切换成标准输出 System.setOut(out); System.out.println("程序运行完毕,请查看日志"); }
结果如下:log.txt文件有如下内容:
控制台输出:程序运行完毕,请查看日志
- 那么setIn()是不是可以改变输入流呢?
public static void main(String[] args) throws Exception { InputStream in = System.in; //缓存标准输入 InputStream ps = new FileInputStream("log.txt"); System.setIn(ps); Scanner scanner = new Scanner(System.in); String line = ""; while (scanner.hasNextLine()) { line = scanner.nextLine(); System.out.println(line); } }
我们发现,标准的输入并不需要我们手动录入了。而是可以直接从文件中读取了,非常的支持定制化需求。
identityHashCode方法、lineSeparator方法、arraycopy方法
说identityHashCode,我们不得不提一个对象的hashCode,因此做如下总结:
一个对象的hashCode和identityHashCode 的关系:
1.对象的hashCode,一般是通过将该对象的内部地址转换成一个整数来实现的
2.当一个类没有重写Object类的hashCode()方法时,它的hashCode和identityHashCode是一致的
3.当一个类重写了Object类的hashCode()方法时,它的hashCode则有重写的实现逻辑决定,此时的hashCode值一般就不再和对象本身的内部地址有相应的哈希关系了
4.当null调用hashCode方法时,会抛出空指针异常,但是调用System.identityHashCode(null)方法时能正常的返回0这个值
5.一个对象的identityHashCode能够始终和该对象的内部地址有一个相对应的关系,从这个角度来讲,它可以用于代表对象的引用地址,所以,在理解==这个操作运算符的时候是比较有用的
所以即使我们重写了hashCode,每个对象的identityHashCode值也会是唯一的。
lineSeparator的使用
换行符。该方法主要解决window系统、linux系统等对换行符定义不一样的问题。之前我们都是这么用:System.getProperty(“line.separator”)。但JDK7为我们提供了一个更为简便的方法:System.lineSeparator()
备注:其实System.lineSeparator()内部调用的还是System.getProperty(“line.separator”)方法。只是使用起来更加方便了
arraycopy方法的使用
显然,又是一个没有遵循驼峰命名的方法名。它是个native方法,所以效率可想而知。因此我们数组拷贝的时候,推荐使用此方法
它可以实现将一个数组的指定个数元素复制到另一个数组中
例如:arraycopy( arr1, 3, arr2, 2, 2);
意思为:将arr1数组里从索引为2的元素开始, 复制到数组arr2里的索引为5的位置, 复制的元素个数为10个.
public static void main(String[] args) throws Exception { Integer[] arr1 = {1, 2, 3, 4, 5}; Integer[] arr2 = new Integer[5]; System.arraycopy(arr1, 3, arr2, 2, 3); System.out.println(Arrays.toString(arr2)); //[null, null, 4, 5, null] }
备注:此处需要注意,任意一个数组的长度被超出范围了,都会抛出异常的:
public static void main(String[] args) throws Exception { Integer[] arr1 = {1, 2, 3, 4, 5}; Integer[] arr2 = new Integer[5]; System.arraycopy(arr1, 3, arr2, 2, 5); System.out.println(Arrays.toString(arr2)); } 抛出异常:java.lang.ArrayIndexOutOfBoundsException
很显然数组arr1的长度就不足3+5,所以就抛出异常了。同样的如果arr2长度不够,也是一样的结果。所以用的最多的,就是同长度的数组拷贝。