java常用类之System

简介: System是一个类,这个System类主要是一些与系统相关的属性和方法的集合,而且其内部的方法全部是静态的,所以我们直接使用System直接调用就好,比如我们常用的一个System.out.print。这篇文章我们就来分析一下System类。

一、System概述


System就是系统的意思。因此它的主要操作肯定也是和系统信息有关。这个类位于java.lang包。可能我们都有一个疑惑,我们从来没见过System被实例化,这是因为System类内部的构造函数是私有的,在外部不能访问,因此也就不能被实例化了。

他主要有如下功能:


(1)系统信息的访问,如外部属性和环境变量等

(2)垃圾回收相关操作

(3)标准输入输出

(4)比较常用的其他操作,比如数组拷贝


接下来我们就对这些功能进行一个测试与描述:


二、System功能演示


1、获取设置属性方法


也就是说我们的System如何获取系统的属性,或者说是调用哪个方法获取属性。


(1)contains(Object value)、containsKey(Object key):判断给定的参数或属性关键字在属性表中有定义,返回True或者False;

(2)getProperty(String key)、getProperty(String key, String default):根据参数获取属性

(3)list(PrintStream s)、list(PrintWriter w): 在输出流中输出属性表内容;

(4)size():返回当前属性表中定义的属性关键字个数。

我们当然可以设置属性:

(1)put(Object key, Object value) :向属性表中追加属性关键字和关键字的值;

(2)remove(Object key) :从属性表中删除关键字。


2、获取系统属性


上面我们可以直接使用System.contains等方法来调用,下面我们可以输入以下参数来获取系统信息。

v2-b54bc3461c00ae38f22be4b37ec4dedb_1440w.jpg

v2-b54bc3461c00ae38f22be4b37ec4dedb_1440w.jpg

v2-dcf1d619b0206ca2ecfcd6c5e8556d6f_1440w.jpg

然后使用代码测试一下几个比较典型的吧:

public class SystemTest {
    public static void main(String[] args) {
        System.out.println("Java 运行时环境版本         :" + System.getProperty("java.version"));
        System.out.println("Java 运行时环境供应商     :" + System.getProperty("java.vendor"));
        System.out.println("Java 运行时环境规范版本    :" + System.getProperty("java.specification.version"));
        System.out.println("Java 运行时环境规范供应商:" + System.getProperty("java.specification.vendor"));
        System.out.println("Java 运行时环境规范名称    :" + System.getProperty("java.specification.name"));
        System.out.println("操作系统的名称:" + System.getProperty("os.name"));
        System.out.println("操作系统的架构:" + System.getProperty("os.arch"));
        System.out.println("操作系统的版本:" + System.getProperty("os.version"));
        System.out.println("用户的账户名称          :" + System.getProperty("user.name"));
        System.out.println("用户的主目录              :" + System.getProperty("user.home"));
        System.out.println("用户的当前工作目录  : " + System.getProperty("user.dir"));
    }
}

当然运行一下我们的控制台就有结果了:

v2-82f4289b7268b0e0538e99dc86d43b1d_1440w.jpg

在这里只是挑选了一部分进行测试,参数已经列出来了,其他的可以自己测。


三、常见操作


1、拷贝数组arraycopy


public class SystemTest {
    public static void main(String[] args) {
        int[] arr1 = {1,2,3,4,5 };
        int[] arr2 = { 6,7,8,9,10};
        /*
         * 第一个参数arr1:被复制的数组
         * 第二个参数1:arr1中要复制的起始位置
         * 第三个参数arr2:目标数组
         * 第四个参数0:目标数组的复制起始位置
         * 第五个参数3:目标数组的复制结束位置
         */
        System.arraycopy(arr1, 1, arr2, 0, 3);
        for (int i = 0; i < 5; i++)
            System.out.print(arr2[i] + " ");
    }
}

2、获取系统时间

public class SystemTest {
    public static void main(String[] args) {
        System.out.println(System.currentTimeMillis());
        System.out.println(System.nanoTime());
    }
}
//输出:1565841056267(时间戳)
//输出:1130607059454400


四、垃圾回收相关操作:System.gc


这句话表明运行了垃圾回收器。java虚拟机会回收一下系统垃圾,比如说没有使用的对象。

public class SystemTest {
    public static void main(String[] args) {
        User user = new User();//新建一个对象
        System.out.println(user.toString());
        user=null;//将引用置为空
        System.gc();//垃圾回收
        System.out.println(user.toString());
    }
}

我们看一下运行结果再来分析

v2-1faf0d0320d63eed925a302a32f97d06_1440w.png

我们可以看到,在进行完垃圾回收之后,再输入User相关信息时由于找不到对象,因此报了空指针异常。


我们进入到System.gc内部看一下,看看内部执行了什么操作,

public static void gc() {
      Runtime.getRuntime().gc();
}

在这里我们可以看到其实是执行了Runtime的垃圾回收操作。我们在进入会发现其实垃圾回收就是Runtime做的。


五、源码分析


1、初始化

我们进入到System的源码中,可以看到首先由这样的描述:

/* register the natives via the static initializer.
 * VM will invoke the initializeSystemClass method to complete
 * the initialization for this class separated from clinit.
 * Note that to use properties set by the VM, see the constraints
 * described in the initializeSystemClass method.
*/
private static native void registerNatives();
static {
    registerNatives();
}
/** Don't let anyone instantiate this class */
private System() {}

上面是什么意思呢?


首先:registerNatives()方法是一个入口方法,注册成了natives,也就是说该方法会令vm通过调用initializeSystemClass方法来完成初始化工作。


然后:构造函数被设置成private,说明我们不能实例化这个类,注释也已经说明了。

既然System初始化的操作是通过initializeSystemClass,我们不如进入到这个类中去看看。

private static void initializeSystemClass() {
        //第一步:初始化props
        props = new Properties();
        initProperties(props);  // initialized by the VM
        //第二步:vm保存删除一些系统属性
        sun.misc.VM.saveAndRemoveProperties(props);
        //第三步:获取系统分隔符
        lineSeparator = props.getProperty("line.separator");
        //第四步:初始化系统的一些配置
        sun.misc.Version.init();
        //第五步:输入输出流初始化
        FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
        FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
        FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
        setIn0(new BufferedInputStream(fdIn));
        setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
        setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));
        loadLibrary("zip");
        //第六步:设置平台相关的信号处理
        Terminator.setup();
        //第七步:初始化系统环境
        sun.misc.VM.initializeOSEnvironment();
        //第八步:把自己添加到线程组
        Thread current = Thread.currentThread();
        current.getThreadGroup().add(current);
        //第九步:初始化
        setJavaLangAccess();
        sun.misc.VM.booted();
 }

通过initializeSystemClass,我们已经能够明白System是如何初始化的,对于每一步,我们可以继续深入下去观察其具体实现,在这里就不赘述了。


2、类属性


类属性其实主要是输入输出流

public final static InputStream in = null;
public final static PrintStream out = null;
public final static PrintStream err = null;


3、类方法


在这里肯定不能所有的方法都讲一遍,在这里列举几个比较重要的方法。

(1)getProperty:获取系统属性

public static String getProperty(String key) {
        //校验key的值
        checkKey(key);
        //检查参数是否安全
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPropertyAccess(key);
        }
        //获取系统属性
        return props.getProperty(key);
}

我们在这里发现,其实获取属性的操作最关键的就是最后一句props.getProperty(key)。我们进入到这个方法看看:

public String getProperty(String key) {
        Object oval = super.get(key);
        String sval = (oval instanceof String) ? (String)oval : null;
        return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
    }

也就是说其实是 一直是回调defaults.getProperty(key),让父类一直不停的去调用。最后返回一个String。

(2)checkKey:校验key

private static void checkKey(String key) {
        if (key == null) {
            throw new NullPointerException("key can't be null");
        }
        if (key.equals("")) {
            throw new IllegalArgumentException("key can't be empty");
        }
}

里面很简单就是看看是否为空。

(3)setProperties:设置系统属性

public static void setProperties(Properties props) {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPropertiesAccess();
        }
        if (props == null) {
            props = new Properties();
            initProperties(props);
        }
        System.props = props;
    }

最核心的就是最后一行,但是前面首先检验了是否是系统安全的属性,而且也根据这个属性初始化了一次。我们进入initProperties。

private static native Properties initProperties(Properties props);

这是一个native方法。

(4)exit():退出当前的jvm

public static void exit(int status) {
     Runtime.getRuntime().exit(status);
}

其实调用的也是runtime的退出方法。

(5)其他方法

public static native long currentTimeMillis();
 public static native long nanoTime();
 public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);
public static native int identityHashCode(Object x);

我们会发现经常操作的这些方法其实也是native的。

(6)安全管理机制

与之相关的方法有三个

public static void setSecurityManager(final SecurityManager s) {
    try {
        s.checkPackageAccess("java.lang");
    } catch (Exception e) {
    }
    setSecurityManager0(s);
}

第二个:

private static synchronized void setSecurityManager0(final SecurityManager s) {
    SecurityManager sm = getSecurityManager();
    if (sm != null) {
        sm.checkPermission(new RuntimePermission ("setSecurityManager"));
    }
    if ((s != null) && (s.getClass().getClassLoader() != null)) {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                s.getClass().getProtectionDomain().implies(SecurityConstants.ALL_PERMISSION);
                return null;
            }
        });
    }
    security = s;
    InetAddressCachePolicy.setIfNotSet(InetAddressCachePolicy.FOREVER);
}

还有最后一个

public static SecurityManager getSecurityManager() {
    return security;
}

OK。源码分析也就先说到这里,对于System类要知道其基本的内部实现以及常用的操作即可。

相关文章
|
5天前
|
Java 关系型数据库 MySQL
Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
【4月更文挑战第12天】Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
33 3
|
1天前
|
人工智能 安全 Java
Java8 - LocalDateTime时间日期类使用详解
Java8 - LocalDateTime时间日期类使用详解
|
2天前
|
安全 Java 程序员
|
3天前
|
Java
Java Class类
Java Class类
8 0
|
10天前
|
Java 编译器
Java Character 类
4月更文挑战第13天
|
10天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
14天前
|
Java Shell
Java 21颠覆传统:未命名类与实例Main方法的编码变革
Java 21颠覆传统:未命名类与实例Main方法的编码变革
13 0
|
14天前
|
Java
Java 15 神秘登场:隐藏类解析未知领域
Java 15 神秘登场:隐藏类解析未知领域
18 0
|
16天前
|
安全 Java
append在Java中是哪个类下的方法
append在Java中是哪个类下的方法
23 9
|
16天前
|
JavaScript Java 测试技术
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
30 0
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)