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 static void setSecurityManager(final SecurityManager s) {
try {
s.checkPackageAccess("java.lang");
} catch (Exception e) {
// no-op
}
setSecurityManager0(s);
}
private static synchronized void 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);
}