java.lang.System源码分析
1.final修饰,不能被继承。构造函数使用private修饰,不能被其他类实例化 public final class System { ... private System() { } ... } 2.成员变量:final修饰,不能被重新赋值 public final static InputStream in = null;//标准输入流,默认已经打开,一般用来响应键盘或者其他用户指定的输入 public final static PrintStream out = null;//标准输出流,默认已经打开,一般用来展示输出 public final static PrintStream err = null;//标准错误输出流,默认已经打开,按照约定,用来输出错误信息 private static native void setIn0(InputStream in);//初始化这些流的工作由本地native方法实现,由系统连接的共享库去实现 private static native void setOut0(PrintStream out); private static native void setErr0(PrintStream err); private static volatile SecurityManager security = null;//系统安全管理器,使用volatile修饰该变量。在初始化IO流时,需要使用安全器校验权限 private static volatile Console cons = null;// 标准输出控制台 3.SecurityManager,安全管理器,用来做访问权限校验 public staticvoid setSecurityManager(final SecurityManager s) { try { s.checkPackageAccess("java.lang"); } catch (Exception e) { // no-op } setSecurityManager0(s); } private static synchronizedvoid setSecurityManager0(final SecurityManager s) { SecurityManager sm = getSecurityManager(); if (sm != null) { // ask the currently installed security manager if we // can replace it. sm.checkPermission(new RuntimePermission("setSecurityManager")); } if ((s != null) && (s.getClass().getClassLoader() != null)) { // New security manager class is not on bootstrap classpath. // Cause policy to get initialized before we install the new // security manager, in order to prevent infinite loops when // trying to initialize the policy (which usually involves // accessing some security and/or system properties, which in turn // calls the installed security manager's checkPermission method // which will loop infinitely if there is a non-system class // (in this case: the new security manager class) on the stack). AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { s.getClass().getProtectionDomain().implies (SecurityConstants.ALL_PERMISSION); return null; } }); } security = s; } private static void checkIO() { SecurityManager sm = getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("setIO")); } } public void checkPermission(Permission perm) { java.security.AccessController.checkPermission(perm); } 4.Console只能用在标准输入、输出流未被重定向的原始控制台中使用 public static Console console() { if (cons == null) { synchronized (System.class) { cons = sun.misc.SharedSecrets.getJavaIOAccess().console();// console是通过sun.misc.SharedSecrets 类获取得到的(作用是从JVM里面获取实例对象) } } return cons; } 5.获取系统时间,都是通过本地native方法实现 public static native long currentTimeMillis();//获取毫秒级的时间戳(1970年1月1日0时起的毫秒数) public static native long nanoTime();//获取纳秒,返回的可能是任意时间(主要用于衡量时间段) 6.数组拷贝 public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length); 此方法在Collection的实现类里面扩容的时候经常被遇到,例如 ArrayList.add(int, E)。 还有另外一个比较常用的数组拷贝的方法:Arrays.copyOf,通过看源码会发现,最后实际调用的也是 Syetem.arraycopy 。 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } 7.获取对象的地址,本地native方法 public static native int identityHashCode(Object x); 当Object的hashCode()被重写的时候,如何获取到对象的地址呢?通过 System.identityHashCode(Object)可以获取到对象的地址。 public class OverrideHashCode { @Override public int hashCode() { //return super.hashCode(); return 0; } } OverrideHashCode overrideHash = new OverrideHashCode(); System.out.println("覆盖之后,hashCode(): " + overrideHash.hashCode()); System.out.println("通过System.identityHashCode()重新获取对象地址: " + System.identityHashCode(overrideHash)); 测试结果: 覆盖之后,hashCode(): 2018699554 //未被重写 通过System.identityHashCode()重新获取对象地址: 2018699554 覆盖之后,hashCode(): 0 //重写后的值 通过System.identityHashCode()重新获取对象地址: 2018699554 8.系统变量 private static Properties props; private static native Properties initProperties(Properties props);//初始化是通过本地方法实现的 public static Properties getProperties() { SecurityManager sm = getSecurityManager(); if (sm != null) {//获取系统变量的时候,需要做权限校验。如果没有权限,会抛出AccessControlException sm.checkPropertiesAccess(); } return 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; } 9.获取操作系统环境变量,用户自己配置的系统变量,也做了权限校验 public static String getenv(String name) { SecurityManager sm = getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("getenv."+name)); } return ProcessEnvironment.getenv(name); } 测试使用: System.out.println(System.getenv("ROCKETMQ_HOME")); 能够获取,之前在Windows中设置的环境变量的值。 10.程序退出,接收一个参数status,0表示正常退出,非零参数表示非正常退出。不管status为何值都会退出程序。和return 相比,return是回到上一层,而System.exit(status)是回到最上层 public static void exit(int status) { Runtime.getRuntime().exit(status);//实际上通过获取Runtime运行时来退出的 } 11.手动调用gc-垃圾回收器,注意调用后不会马上发生消息回收,JVM会在适合的时候触发GC public static void gc() { Runtime.getRuntime().gc(); } 12.加载动态库(Windows下面是dll文件),用来装载库文件,不论是JNI库文件还是非JNI库文件 @CallerSensitive public static void load(String filename) {// fileName一定要是绝对路径,否则会抛出UnsatisfiedLinkError Runtime.getRuntime().load0(Reflection.getCallerClass(), filename); } @CallerSensitive public static void loadLibrary(String libname) { Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname); } 好了,Syetem的代码就这么多~