深入分析java中的System类

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

(想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!)

一、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等方法来调用,下面我们可以输入以下参数来获取系统信息。

功能描述
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用户的当前工作目录

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

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"));
	}
}

当然运行一下我们的控制台就有结果了:
在这里插入图片描述
在这里只是挑选了一部分进行测试,参数已经列出来了,其他的可以自己测。

三、常见操作

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());
	}
}

我们看一下运行结果再来分析
在这里插入图片描述
我们可以看到,在进行完垃圾回收之后,再输入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类要知道其基本的内部实现以及常用的操作即可。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值