java system 源码_一起学JDK源码 -- System类

查看所有目录

说起System类,对我们来说既熟悉又陌生,熟悉的是我们刚接触java时就会用到这个类,甚至每天写代码也会用到这个类(System.out.println());陌生的是我们对这个类一知半解,它是如何实现的,为什么这样写就能在屏幕上输出东西。今天就让我们通过阅读它的源码揭开它那神秘的面纱。

基础知识:

深拷贝与浅拷贝:

浅拷贝:只是简单的对对象的引用进行复制。

深拷贝:拷贝对象的值和对象的内容。

类定义:

public final class System {}

System类是被final修饰的,不能被继承。

成员变量:

//标准输入流,一般接收键盘输入

public final static InputStream in = null;

//标准输出流,向控制台输出正确信息

public final static PrintStream out = null

//标准输出流,向控制台输出错误信息

public final static PrintStream err = null;

//安全管理器,用volatile关键字修饰,表示对象在多个线程间可见

private static volatile SecurityManager security = null;

//JAVA控制台对象与JAVA虚拟机相联,接收控制台输入,或向控制台输出信息。只能在控制台运行代码,否则获得对象为null。

private static volatile Console cons = null;

//用于承装系统属性,如os.name os.version等

private static Properties props;

//换行符widows返回"\r\n",UNIX系统返回"\n"

private static String lineSeparator;

看到这些成员变量,有些是公有的,有些是私有的。这些对象被赋值为null,而且有的被final修饰不能被重新赋值。找遍整个类也没看到在哪里初始化这些对象。但我们使用System.out.println();的时候并没有报错啊。能够使用,就说明对象在谋个时刻被创建了,那到底这些对象是什么时候被创建的呢。怀着无比好奇的心理,在类中查找,忽然我看到了如下代码。

static {

registerNatives();

private static native void registerNatives();

静态代码块,类被加载的时候执行,会不会这些对象是在registerNatives方法中创建的呢。再一看这个方法是本地方法。看下注释,也看不懂,但隐约能看到VM啊,initializer啊,initializeSystemClass method之类的,找了一下,发现类中有一个initializeSystemClass方法,大概能猜到,是VM会执行这个方法。

private static void initializeSystemClass() {

props = new Properties();

initProperties(props); // initialized by the 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();

}

在这个方法中可以看到刚才那些对象都是在这里被创建的。

lineSeparator = props.getProperty("line.separator");从系统中获取换行符。

setIn0(new BufferedInputStream(fdIn));设置标准输入流,也就是创建in对象,追溯到源头也就是创建了FileDescriptor.in对象,这个对象用于操作标准输入流,再往深了就到了虚拟机内部实现细节了,这里就有展开了,有兴趣的同学可以自行研究。

其它的对象像out、err创建过程同in类似。到这里我们终于明白了为什么执行System.out.println()时会向控制台输出东西了。

构造函数:

private System() {

}

可以看到System类就一个构造函数,而且被私有化了,不允许我们创建对象。如果要使用这个类,只能使用类中的一些静态成员。这也是java中单例模式的雏形,把构造私有化,然后对外提供一个内部创建的唯一的对象,就形成单例了。

其它函数:

setIn:

public static void setIn(InputStream in) {

checkIO();

setIn0(in);

}

//对setIo进行安全检查

private static void checkIO() {

SecurityManager sm = getSecurityManager();

if (sm != null) {

sm.checkPermission(new RuntimePermission("setIO"));

}

}

//给System.in重新赋值,内部实现。

private static native void setIn0(InputStream in);

给System.in对象重新赋值。即当调用了些方法后,我们再使用System.in的时候接收的信息不再是从键盘录入了,而是我们指定的文件或设备。点开函数可以看到,第一个函数是进行安全检查的,第二个函数是调用的本地方法。有人疑惑System.in变量不是被final修饰了吗,为什么还可以被修改。额...这个...它调用的是本地方法,由虚拟机内部实现,他是老大能不能改变他说了算。

setOut:

public static void setOut(PrintStream out) {

checkIO();

setOut0(out);

}

给System.out重新赋值,原理同setIn。比如我们想让System.out.println()把内容输出到文件,就可以调用这个方法,指定输出文件。

setErr:

public static void setErr(PrintStream err) {

checkIO();

setErr0(err);

}

给System.err重新赋值,原理同setOut。

console:

public static Console console() {

if (cons == null) {

synchronized (System.class) {

cons = sun.misc.SharedSecrets.getJavaIOAccess().console();

}

}

return cons;

}

返回唯一的Console对象,这个对象是跟Java虚拟机相关联的。可以看到这里使用了synchronized代码块,避免多线程调用的时候返回多个Console对象。

inheritedChannel:

public static Channel inheritedChannel() throws IOException {

return SelectorProvider.provider().inheritedChannel();

}

返回从创建此 java 虚拟机的实体中继承的通道。如果有则返回,没有返回null。

SecurityManager设置与获取:

public static void setSecurityManager(final SecurityManager s) {

try {

s.checkPackageAccess("java.lang");

} catch (Exception e) {

// no-op

}

setSecurityManager0(s);

}

public static SecurityManager getSecurityManager() {

return security;

}

设置和获取java的安全管理器,当运行未知的Java程序的时候,该程序可能有操作如删除系统文件、重启系统等,为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时候就要启用Java安全管理器。

currentTimeMillis:

public static native long currentTimeMillis();

获取当前系统时间的毫秒数。1秒=1000毫秒(ms);

nanoTime:

public static native long nanoTime();

获取当前系统时间的纳秒数。1秒=1,000,000,000 纳秒(ns);

arraycopy:

public static native void arraycopy(

Object src,//源数组

int srcPos, //源数组要复制的起始位置

Object dest, //目标数组

int destPos, //目标数组的起始位置

int length//复制的长度

);

复制数组,从一个明确的数组中复制数组元素到另一个数组中。System.arraycopy采用的是浅复制,使用的时候注意一下。

identityHashCode:

public static native int identityHashCode(Object x);

获取对象的hashCode,一般可通过对象的hashCode()方法获取对象的hashCode,但有些对象重写了hashCode()方法,那么想要获取对象的hashCode时就要使用本方法了。

props:

private static Properties props;

private static native Properties initProperties(Properties props);

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;

}

public static Properties getProperties() {

SecurityManager sm = getSecurityManager();

if (sm != null) {

sm.checkPropertiesAccess();

}

return props;

}

props是用于承装java的系统变量的,initProperties是初始化props对象,本地方法实现。setProperties()重新设置系统的Properties对象。getProperties()方法用于获取Properties对象。不论是设置还是获取都先会进行安全检查,看是否对系统属性有安全限制。获取Properties对象后可重新设值取值。

public static String setProperty(String key, String value) {

checkKey(key);

SecurityManager sm = getSecurityManager();

if (sm != null) {

sm.checkPermission(new PropertyPermission(key,

SecurityConstants.PROPERTY_WRITE_ACTION));

}

return (String) props.setProperty(key, value);

}

设置系统属性到Properties对象中,如果已经存在则覆盖原有属性,并返回原有属性。该对象是全局的,在程序中到处都可以调用。

getProperty:

public static String getProperty(String key) {

checkKey(key);

SecurityManager sm = getSecurityManager();

if (sm != null) {

sm.checkPropertyAccess(key);

}

return props.getProperty(key);

}

从Properties中获取系统属性,如果有则返回,如果没有返回null。

getProperty(String key, String def):

public static String getProperty(String key, String def) {

checkKey(key);

SecurityManager sm = getSecurityManager();

if (sm != null) {

sm.checkPropertyAccess(key);

}

return props.getProperty(key, def);

}

从Properties中获取系统属性,如果有则返回,如果没有返回默认值,第二个参数为默认值。

clearProperty:

public static String clearProperty(String key) {

checkKey(key);

SecurityManager sm = getSecurityManager();

if (sm != null) {

sm.checkPermission(new PropertyPermission(key, "write"));

}

return (String) props.remove(key);

}

用于清除系统属性,并返回原属性值。

lineSeparator:

public static String lineSeparator() {

return lineSeparator;

}

获取系统的换行符widows系统返回"\r\n",UNIX系统返回"\n"。

getenv:

public static java.util.Map getenv() {

SecurityManager sm = getSecurityManager();

if (sm != null) {

sm.checkPermission(new RuntimePermission("getenv.*"));

}

return ProcessEnvironment.getenv();

}

获取java程序环境信息,如LOCALAPPDATA,JAVA_HOME等。返回的是一个Map对象。

exit:

public static void exit(int status) {

Runtime.getRuntime().exit(status);

}

结束当前正在运行中的java虚拟机。参数0代表正常退出,非0代表异常退出。

gc:

public static void gc() {

Runtime.getRuntime().gc();

}

该方法用于告知虚拟机进行垃圾回收。垃圾收集器将运行以回收未使用的内存空间。注意这一步只是通知虚拟机要进行垃圾回收操作,虚拟机并不一定立即进行回收操作。

runFinalization:

public static void runFinalization() {

Runtime.getRuntime().runFinalization();

}

我们知道Object对象不有一个finalize方法,当进行垃圾回收时,对象被回收前会执行finalize方法。调用runFinalization方法运行处于挂起终止状态的所有对象的终止方法。Java虚拟机已经尽最大努力去完成所有未执行的终止方法。

load:

public static void load(String filename) {

Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);

}

用于装载指定名称filename的系统库文件。filename必需是绝对路径。

loadLibrary:

public static void loadLibrary(String libname) {

Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);

}

加载系统中的本地库,如果是Windows系统加载的是xxx.dll,如果是unix系统加载的是xxx.so,注意该方法不能包含文件的扩展名,但该文件必需在JVM属性java.library.path所指向的路径中。

mapLibraryName:

public static native String mapLibraryName(String libname);

将一个库名称映射到特定于平台的、表示本机库的字符串中。有点抽象,比如你想映射mapLibraryName这个库名,映射到Windows平台就是mapLibraryName.dll映射到Unix平台就是mapLibraryName.so

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值