【小家java】聊聊Java中的System类


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长度不够,也是一样的结果。所以用的最多的,就是同长度的数组拷贝。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券