【Java原理系列】 Java 中System原理用法示例源码详解
原理
System
类的名字来源于操作系统中的概念,表示整个计算机系统的环境和资源。Java 中的 System
类提供了访问和操作与系统相关的功能和属性的方法。
Java 的 System
类是由 Java 核心库提供的,它使用本地代码实现了与底层操作系统交互的功能。这些本地方法通过 Java Native Interface(JNI)来调用底层操作系统的特定功能。
System
类的原理可以分为以下几个方面:
-
标准输入、输出和错误流:
System
类提供了对标准输入流(System.in
)、标准输出流(System.out
)和标准错误流(System.err
)的访问和操作。这些流与底层操作系统的输入和输出流相关联。 -
系统属性:
System
类提供了获取和设置系统属性的方法,如getProperty()
和setProperty()
。系统属性是一种键值对形式的配置信息,可以用于获取和设置与系统相关的信息,如操作系统类型、文件路径分隔符等。 -
本地库加载和映射:
System
类提供了加载本地库和映射本地库的方法,如load()
和loadLibrary()
。本地库是由其他编程语言(如 C、C++)编写的动态链接库(DLL 或共享库),可以在 Java 中调用其中的函数。 -
垃圾收集器和内存管理:
System
类提供了运行垃圾收集器的方法gc()
,用于尽力回收未使用的对象以释放内存。此外,System
类还提供了一些与内存管理相关的方法,如arraycopy()
和identityHashCode()
。 -
Java 虚拟机的控制:
System
类提供了一些与 Java 虚拟机控制相关的方法,如exit()
和runFinalization()
。这些方法允许程序在特定条件下终止虚拟机或执行一些必要的清理操作。
通过调用 System
类的静态方法和访问其常量,Java 程序可以直接与底层操作系统交互和配置。这使得开发人员可以更灵活地操作和控制程序的执行环境。
总之,System
类是 Java 核心库中的一个关键类,提供了与系统操作和配置相关的功能和属性。它通过本地代码实现与底层操作系统的交互,并通过静态方法和常量为开发人员提供了方便的接口。
用法总结
System
类是 Java 核心库中的一个 final 类,提供了与系统操作和配置相关的静态方法和常量。下面是对 System
类常用方法的总结:
-
标准输入、输出和错误流:
System.in
:标准输入流,用于从控制台读取用户输入。System.out
:标准输出流,用于向控制台打印输出信息。System.err
:标准错误流,用于向控制台打印错误信息。
-
系统属性:
System.getProperty(String key)
:获取指定系统属性的值。System.setProperty(String key, String value)
:设置指定系统属性的值。
-
加载本地库和本地库映射:
System.load(String filename)
:加载指定文件名的本地库。System.loadLibrary(String libname)
:加载指定名称的本地库。
-
垃圾收集器和内存管理:
System.gc()
:运行垃圾收集器,尽力回收未使用的对象以释放内存。System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
:将一个数组中的元素复制到另一个数组中。
-
Java 虚拟机的控制:
System.exit(int status)
:终止当前正在运行的 Java 虚拟机,并返回指定的状态码。System.currentTimeMillis()
:返回当前时间的毫秒数。System.identityHashCode(Object obj)
:返回指定对象的哈希码值。
-
其他常用方法:
System.arraycopy()
:将一个数组中的元素复制到另一个数组中。System.nanoTime()
:返回当前系统时间的纳秒数。System.getenv(String name)
:获取指定环境变量的值。System.getProperties()
:获取所有系统属性的集合。
System
类的常量包括:
System.out
和System.err
:标准输出和错误流。System.in
:标准输入流。System.lineSeparator()
:换行符(与平台相关)。
通过使用 System
类的这些方法,可以实现对系统属性、输入输出流、本地库加载等功能的访问和控制。
这是 System
类的一些常用方法和常量的总结。根据具体的需求,您可以选择适当的方法来进行系统操作和配置。
示例
下面是对 System
类常用方法的示例用法:
- 标准输入、输出和错误流:
// 从标准输入读取用户输入
Scanner scanner = new Scanner(System.in);
System.out.print("请输入您的姓名:");
String name = scanner.nextLine();
System.out.println("您好," + name);
// 向标准输出打印信息
System.out.println("这是一条输出信息");
// 向标准错误流打印错误信息
System.err.println("发生了一个错误");
- 系统属性:
// 获取指定系统属性的值
String javaVersion = System.getProperty("java.version");
System.out.println("Java 版本:" + javaVersion);
// 设置系统属性的值
System.setProperty("user.dir", "/path/to/directory");
- 加载本地库和本地库映射:
// 加载指定文件名的本地库
System.load("/path/to/library.so");
// 加载指定名称的本地库
System.loadLibrary("libraryName");
- 垃圾收集器和内存管理:
// 运行垃圾收集器
System.gc();
// 将一个数组中的元素复制到另一个数组中
int[] sourceArray = {1, 2, 3, 4, 5};
int[] destinationArray = new int[5];
System.arraycopy(sourceArray, 0, destinationArray, 0, sourceArray.length);
- Java 虚拟机的控制:
// 终止当前正在运行的 Java 虚拟机
System.exit(0);
// 获取当前时间的毫秒数
long currentTime = System.currentTimeMillis();
// 返回指定对象的哈希码值
Object obj = new Object();
int hashCode = System.identityHashCode(obj);
- 其他常用方法:
// 将一个数组中的元素复制到另一个数组中
int[] sourceArray = {1, 2, 3, 4, 5};
int[] destinationArray = new int[5];
System.arraycopy(sourceArray, 0, destinationArray, 0, sourceArray.length);
// 获取当前系统时间的纳秒数
long nanoTime = System.nanoTime();
// 获取指定环境变量的值
String homeDirectory = System.getenv("HOME");
// 获取所有系统属性的集合
Properties properties = System.getProperties();
中文源码
/**
* <code>System</code> 类包含一些有用的类字段和方法。它不能被实例化。
*
* <p><code>System</code> 类提供了标准输入、标准输出和错误输出流;
* 访问外部定义的属性和环境变量;加载文件和库的方式;以及快速复制数组的实用方法等功能。
*
* 作者:未指定
* @since JDK1.0
*/
public final class System {
/* 通过静态初始化程序注册本地方法。
*
* 虚拟机将调用 initializeSystemClass 方法来完成
* 与 clinit 分离的此类的初始化。
* 注意,要使用虚拟机设置的属性,请参见 initializeSystemClass 方法中的限制描述。
*/
private static native void registerNatives();
static {
registerNatives();
}
/** 不允许任何人实例化该类 */
private System() {
}
/**
* "标准"输入流。该流已经打开并准备好提供输入数据。
* 通常,此流对应于键盘输入或主机环境或用户指定的其他输入源。
*/
public final static InputStream in = null;
/**
* "标准"输出流。该流已经打开并准备接受输出数据。
* 通常,此流对应于显示输出或主机环境或用户指定的其他输出目标。
*
* 对于简单的独立 Java 应用程序,输出一行数据的典型方式是:
* <blockquote><pre>
* System.out.println(data)
* </pre></blockquote>
*
* 请参见 <code>PrintStream</code> 类中的 <code>println</code> 方法。
*
* @see java.io.PrintStream#println()
* @see java.io.PrintStream#println(boolean)
* @see java.io.PrintStream#println(char)
* @see java.io.PrintStream#println(char[])
* @see java.io.PrintStream#println(double)
* @see java.io.PrintStream#println(float)
* @see java.io.PrintStream#println(int)
* @see java.io.PrintStream#println(long)
* @see java.io.PrintStream#println(java.lang.Object)
* @see java.io.PrintStream#println(java.lang.String)
*/
public final static PrintStream out = null;
/**
* "标准"错误输出流。该流已经打开并准备接受输出数据。
* 通常,此流对应于显示输出或主机环境或用户指定的其他输出目标。
* <p>
* 根据惯例,此输出流用于显示错误消息或其他需要立即引起用户注意的信息,
* 即使主要输出流(变量 <code>out</code> 的值)已被重定向到文件或其他通常不会持续监视的目标。
*/
public final static PrintStream err = null;
/* 系统的安全管理器。
*/
private static volatile SecurityManager security = null;
/**
* 重新分配 "标准"输入流。
*
* <p>首先,如果存在安全管理器,则使用 <code>RuntimePermission("setIO")</code> 权限调用其
* <code>checkPermission</code> 方法,以查看是否允许重新分配 "标准" 输入流。
* <p>
*
* @param in 新的标准输入流。
*
* @throws SecurityException
* 如果存在安全管理器,并且其 <code>checkPermission</code> 方法不允许重新分配标准输入流。
*
* @see SecurityManager#checkPermission
* @see java.lang.RuntimePermission
*
* @since JDK1.1
*/
public static void setIn(InputStream in) {
checkIO();
setIn0(in);
}
/**
* 重新分配 "标准"输出流。
*
* <p>首先,如果存在安全管理器,则使用 <code>RuntimePermission("setIO")</code> 权限调用其
* <code>checkPermission</code> 方法,以查看是否允许重新分配 "标准" 输出流。
*
* @param out 新的标准输出流
*
* @throws SecurityException
* 如果存在安全管理器,并且其 <code>checkPermission</code> 方法不允许重新分配标准输出流。
*
* @see SecurityManager#checkPermission
* @see java.lang.RuntimePermission
*
* @since JDK1.1
*/
public static void setOut(PrintStream out) {
checkIO();
setOut0(out);
}
/**
* 重新分配 "标准"错误输出流。
*
* <p>首先,如果存在安全管理器,则使用 <code>RuntimePermission("setIO")</code> 权限调用其
* <code>checkPermission</code> 方法,以查看是否允许重新分配 "标准" 错误输出流。
*
* @param err 新的标准错误输出流。
*
* @throws SecurityException
* 如果存在安全管理器,并且其 <code>checkPermission</code> 方法不允许重新分配标准错误输出流。
*
* @see SecurityManager#checkPermission
* @see java.lang.RuntimePermission
*
* @since JDK1.1
*/
public static void setErr(PrintStream err) {
checkIO();
setErr0(err);
}
private static volatile Console cons = null;
/**
* 返回与当前 Java 虚拟机关联的唯一 {@link java.io.Console Console} 对象(如果有)。
*
* @return 系统控制台对象,如果没有则返回 <tt>null</tt>。
*
* @since 1.6
*/
public static Console console() {
if (cons == null) {
synchronized (System.class) {
cons = sun.misc.SharedSecrets.getJavaIOAccess().console();
}
}
return cons;
}
/**
* 返回从创建此 Java 虚拟机的实体继承的通道。
*
* <p>此方法返回通过调用系统范围的默认
* {@link java.nio.channels.spi.SelectorProvider} 对象的
* {@link java.nio.channels.spi.SelectorProvider#inheritedChannel
* inheritedChannel} 方法获得的通道。</p>
*
* <p>除了 {@link java.nio.channels.spi.SelectorProvider#inheritedChannel
* inheritedChannel} 中描述的面向网络的通道外,
* 该方法未来可能会返回其他类型的通道。</p>
*
* @return 继承的通道,如果没有则返回 <tt>null</tt>。
*
* @throws IOException
* 如果发生 I/O 错误
*
* @throws SecurityException
* 如果存在安全管理器并且不允许访问该通道。
*
* @since 1.5
*/
public static Channel inheritedChannel() throws IOException {
return SelectorProvider.provider().inheritedChannel();
}
private static void checkIO() {
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setIO"));
}
}
private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);
/**
* 设置系统安全管理器。
*
* <p>如果已经安装了安全管理器,此方法首先使用
* <code>RuntimePermission("setSecurityManager")</code> 权限调用安全管理器的
* <code>checkPermission</code> 方法,以确保替换现有的安全管理器是允许的。
* 这可能导致抛出 <code>SecurityException</code>。</p>
*
* <p>否则,将参数作为当前安全管理器。如果参数为 <code>null</code>,
* 且未建立安全管理器,则不执行任何操作,方法直接返回。</p>
*
* @param s 安全管理器。
* @exception SecurityException 如果安全管理器已经被设置,并且其
* <code>checkPermission</code> 方法不允许替换它。
* @see #getSecurityManager
* @see SecurityManager#checkPermission
* @see java.lang.RuntimePermission
*/
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)) {
// 新安全管理器类不在引导类路径上。
// 在安装新安全管理器之前,导致策略在初始化时进行初始化,
// 以防止无限循环(通常涉及访问一些安全和/或系统属性,
// 这又调用已安装的安全管理器的 checkPermission 方法,
// 如果堆栈上存在非系统类(在这种情况下:新安全管理器类),
// 则会产生无限循环)。
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
s.getClass().getProtectionDomain().implies(SecurityConstants.ALL_PERMISSION);
return null;
}
});
}
security = s;
}
}
/**
* 获取系统安全管理器。
*
* @return 如果当前应用程序已经建立了安全管理器,则返回该安全管理器;
* 否则返回 <code>null</code>。
* @see #setSecurityManager
*/
public static SecurityManager getSecurityManager() {
return security;
}
/**
* 返回当前时间的毫秒数。请注意,返回值的时间单位是毫秒,
* 值的精度取决于底层操作系统,并且可能更大。例如,许多操作系统以十毫秒为单位计时。
*
* <p>有关“计算机时间”与协调世界时(UTC)之间可能出现的微小差异的讨论,请参见类
* <code>Date</code> 的描述。
*
* @return 当前时间与 1970 年 1 月 1 日午夜 UTC 之间的差异,以毫秒为单位。
* @see java.util.Date
*/
public static native long currentTimeMillis();
/**
* 返回正在运行的 Java 虚拟机的高分辨率时间源的当前值,以纳秒为单位。
*
* <p>此方法只能用于测量经过的时间,与任何其他系统或挂钟时间概念无关。
* 返回的值表示自某个固定但任意的 <i>原点</i> 时间(可能在未来,因此值可能为负)以来的纳秒数。
* 所有调用此方法的 Java 虚拟机实例都使用相同的原点;其他虚拟机实例可能使用不同的原点。
*
* <p>此方法提供了纳秒精度,但不一定具有纳秒分辨率(即值的更改频率) - 除了至少与
* {@link #currentTimeMillis()} 相同的分辨率外,不提供任何保证。
*
* <p>跨越大约 292 年(2^63 纳秒)的连续调用差异将无法正确计算经过的时间,
* 因为会发生数值溢出。
*
* <p>只有在计算同一 Java 虚拟机实例内获得的两个这样的值之间的差异时,此方法返回的值才有意义。
*
* <p>例如,要测量某段代码执行所需的时间:
* <pre> {@code
* long startTime = System.nanoTime();
* // ... 需要测量的代码 ...
* long estimatedTime = System.nanoTime() - startTime;}</pre>
*
* <p>要比较两个 nanoTime 值:
* <pre> {@code
* long t0 = System.nanoTime();
* ...
* long t1 = System.nanoTime();}</pre>
*
* 应该使用 {@code t1 - t0 < 0},而不是 {@code t1 < t0},因为可能会发生数值溢出的情况。
*
* @return 正在运行的 Java 虚拟机的高分辨率时间源的当前值,以纳秒为单位
* @since 1.5
*/
public static native long nanoTime();
/**
* 将源数组中从指定位置开始的一部分复制到目标数组的指定位置。
* 从源数组 <code>src</code> 的 <code>srcPos</code> 位置开始的子序列将被复制到目标数组
* <code>dest</code> 的 <code>destPos</code> 位置。要复制的元素数量等于 <code>length</code> 参数。
* 源数组中从位置 <code>srcPos</code> 到 <code>srcPos+length-1</code> 的元素将复制到
* 目标数组中从位置 <code>destPos</code> 到 <code>destPos+length-1</code>。
* <p>
* 如果 <code>src</code> 和 <code>dest</code> 参数引用同一个数组对象,
* 则复制过程将按照如下方式进行:首先,将源数组中从位置 <code>srcPos</code> 到 <code>srcPos+length-1</code>
* 的元素复制到一个临时数组中,该临时数组有 <code>length</code> 个元素;
* 然后将临时数组的内容复制到目标数组中从位置 <code>destPos</code> 到 <code>destPos+length-1</code>。
* <p>
* 如果 <code>dest</code> 是 <code>null</code>,则抛出 <code>NullPointerException</code>。
* <p>
* 如果 <code>src</code> 是 <code>null</code>,则抛出 <code>NullPointerException</code>,
* 并且不修改目标数组。
* <p>
* 否则,如果满足以下任何一种情况,则抛出 <code>ArrayStoreException</code>,并且不修改目标数组:
* <ul>
* <li><code>src</code> 参数引用非数组对象。
* <li><code>dest</code> 参数引用非数组对象。
* <li><code>src</code> 参数和 <code>dest</code> 参数引用的数组具有不同的基本类型。
* <li><code>src</code> 参数引用具有原始组件类型的数组,并且 <code>dest</code> 参数引用具有引用组件类型的数组。
* <li><code>src</code> 参数引用具有引用组件类型的数组,并且 <code>dest</code> 参数引用具有原始组件类型的数组。
* </ul>
* <p>
* 否则,如果满足以下任何一种情况,则抛出 <code>IndexOutOfBoundsException</code>,并且不修改目标数组:
* <ul>
* <li><code>srcPos</code> 参数为负数。
* <li><code>destPos</code> 参数为负数。
* <li><code>length</code> 参数为负数。
* <li><code>srcPos+length</code> 大于源数组的长度 <code>src.length</code>。
* <li><code>destPos+length</code> 大于目标数组的长度 <code>dest.length</code>。
* </ul>
* <p>
* 否则,如果源数组中从位置 <code>srcPos</code> 到 <code>srcPos+length-1</code> 的任何实际元素
* 无法通过赋值转换转换为目标数组的组件类型,将抛出 <code>ArrayStoreException</code>。
* 在这种情况下,让 <b><i>k</i></b> 是小于 length 的最小非负整数,
* 使得 <code>src[srcPos+</code><i>k</i><code>]</code> 无法转换为目标数组的组件类型;
* 当抛出异常时,源数组中从位置 <code>srcPos</code> 到 <code>srcPos+</code><i>k</i><code>-1</code>
* 的元素已经复制到目标数组中从位置 <code>destPos</code> 到 <code>destPos+</code><i>k</I><code>-1</code>,
* 并且目标数组的其他位置未被修改。
* (由于已列出的限制,此段落仅适用于两个数组都具有引用类型组件的情况。)
*
* @param src 源数组。
* @param srcPos 源数组中的起始位置。
* @param dest 目标数组。
* @param destPos 目标数据中的起始位置。
* @param length 要复制的数组元素数量。
* @exception IndexOutOfBoundsException 如果复制会导致访问超出数组边界的数据。
* @exception ArrayStoreException 如果 <code>src</code> 数组中的元素由于类型不匹配而无法存储到
* <code>dest</code> 数组中。
* @exception NullPointerException 如果 <code>src</code> 或 <code>dest</code> 中有任一参数为 <code>null</code>。
*/
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
/**
* 返回与给定对象相同的哈希码,就像默认方法 hashCode() 返回的那样,
* 无论给定对象的类是否重写了 hashCode()。
* 空引用的哈希码为零。
*
* @param x 要计算哈希码的对象
* @return 哈希码
* @since JDK1.1
*/
public static native int identityHashCode(Object x);
/**
* 系统属性。以下属性已被保证定义:
* <dl>
* <dt>java.version <dd>Java 版本号
* <dt>java.vendor <dd>Java 供应商特定字符串
* <dt>java.vendor.url <dd>Java 供应商 URL
* <dt>java.home <dd>Java 安装目录
* <dt>java.class.version <dd>Java 类版本号
* <dt>java.class.path <dd>Java 类路径
* <dt>os.name <dd>操作系统名称
* <dt>os.arch <dd>操作系统体系结构
* <dt>os.version <dd>操作系统版本
* <dt>file.separator <dd>文件分隔符(Unix 上为“/”)
* <dt>path.separator <dd>路径分隔符(Unix 上为“:”)
* <dt>line.separator <dd>行分隔符(Unix 上为“\n”)
* <dt>user.name <dd>用户帐户名
* <dt>user.home <dd>用户主目录
* <dt>user.dir <dd>用户的当前工作目录
* </dl>
*/
private static Properties props;
private static native Properties initProperties(Properties props);
/**
* Determines the current system properties.
* <p>
* First, if there is a security manager, its
* <code>checkPropertiesAccess</code> method is called with no
* arguments. This may result in a security exception.
* <p>
* The current set of system properties for use by the
* {@link #getProperty(String)} method is returned as a
* <code>Properties</code> object. If there is no current set of
* system properties, a set of system properties is first created and
* initialized. This set of system properties always includes values
* for the following keys:
* <table summary="Shows property keys and associated values">
* <tr><th>Key</th>
* <th>Description of Associated Value</th></tr>
* <tr><td><code>java.version</code></td>
* <td>Java Runtime Environment version</td></tr>
* <tr><td><code>java.vendor</code></td>
* <td>Java Runtime Environment vendor</td></tr>
* <tr><td><code>java.vendor.url</code></td>
* <td>Java vendor URL</td></tr>
* <tr><td><code>java.home</code></td>
* <td>Java installation directory</td></tr>
* <tr><td><code>java.vm.specification.version</code></td>
* <td>Java Virtual Machine specification version</td></tr>
* <tr><td><code>java.vm.specification.vendor</code></td>
* <td>Java Virtual Machine specification vendor</td></tr>
* <tr><td><code>java.vm.specification.name</code></td>
* <td>Java Virtual Machine specification name</td></tr>
* <tr><td><code>java.vm.version</code></td>
* <td>Java Virtual Machine implementation version</td></tr>
* <tr><td><code>java.vm.vendor</code></td>
* <td>Java Virtual Machine implementation vendor</td></tr>
* <tr><td><code>java.vm.name</code></td>
* <td>Java Virtual Machine implementation name</td></tr>
* <tr><td><code>java.specification.version</code></td>
* <td>Java Runtime Environment specification version</td></tr>
* <tr><td><code>java.specification.vendor</code></td>
* <td>Java Runtime Environment specification vendor</td></tr>
* <tr><td><code>java.specification.name</code></td>
* <td>Java Runtime Environment specification name</td></tr>
* <tr><td><code>java.class.version</code></td>
* <td>Java class format version number</td></tr>
* <tr><td><code>java.class.path</code></td>
* <td>Java class path</td></tr>
* <tr><td><code>java.library.path</code></td>
* <td>List of paths to search when loading libraries</td></tr>
* <tr><td><code>java.io.tmpdir</code></td>
* <td>Default temp file path</td></tr>
* <tr><td><code>java.compiler</code></td>
* <td>Name of JIT compiler to use</td></tr>
* <tr><td><code>java.ext.dirs</code></td>
* <td>Path of extension directory or directories
* <b>Deprecated.</b> <i>This property, and the mechanism
* which implements it, may be removed in a future
* release.</i> </td></tr>
* <tr><td><code>os.name</code></td>
* <td>Operating system name</td></tr>
* <tr><td><code>os.arch</code></td>
* <td>Operating system architecture</td></tr>
* <tr><td><code>os.version</code></td>
* <td>Operating system version</td></tr>
* <tr><td><code>file.separator</code></td>
* <td>File separator ("/" on UNIX)</td></tr>
* <tr><td><code>path.separator</code></td>
* <td>Path separator (":" on UNIX)</td></tr>
* <tr><td><code>line.separator</code></td>
* <td>Line separator ("\n" on UNIX)</td></tr>
* <tr><td><code>user.name</code></td>
* <td>User's account name</td></tr>
* <tr><td><code>user.home</code></td>
* <td>User's home directory</td></tr>
* <tr><td><code>user.dir</code></td>
* <td>User's current working directory</td></tr>
* </table>
* <p>
* Multiple paths in a system property value are separated by the path
* separator character of the platform.
* <p>
* Note that even if the security manager does not permit the
* <code>getProperties</code> operation, it may choose to permit the
* {@link #getProperty(String)} operation.
*
* @return the system properties
* @exception SecurityException if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow access
* to the system properties.
* @see #setProperties
* @see java.lang.SecurityException
* @see java.lang.SecurityManager#checkPropertiesAccess()
* @see java.util.Properties
*/
public static Properties getProperties() {
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
return props;
}
/**
* Returns the system-dependent line separator string. It always
* returns the same value - the initial value of the {@linkplain
* #getProperty(String) system property} {@code line.separator}.
*
* <p>On UNIX systems, it returns {@code "\n"}; on Microsoft
* Windows systems it returns {@code "\r\n"}.
*
* @return the system-dependent line separator string
* @since 1.7
*/
public static String lineSeparator() {
return lineSeparator;
}
private static String lineSeparator;
/**
* Sets the system properties to the <code>Properties</code>
* argument.
* <p>
* First, if there is a security manager, its
* <code>checkPropertiesAccess</code> method is called with no
* arguments. This may result in a security exception.
* <p>
* The argument becomes the current set of system properties for use
* by the {@link #getProperty(String)} method. If the argument is
* <code>null</code>, then the current set of system properties is
* forgotten.
*
* @param props the new system properties.
* @exception SecurityException if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow access
* to the system properties.
* @see #getProperties
* @see java.util.Properties
* @see java.lang.SecurityException
* @see java.lang.SecurityManager#checkPropertiesAccess()
*/
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;
}
/**
* Gets the system property indicated by the specified key.
* <p>
* First, if there is a security manager, its
* <code>checkPropertyAccess</code> method is called with the key as
* its argument. This may result in a SecurityException.
* <p>
* If there is no current set of system properties, a set of system
* properties is first created and initialized in the same manner as
* for the <code>getProperties</code> method.
*
* @param key the name of the system property.
* @return the string value of the system property,
* or <code>null</code> if there is no property with that key.
*
* @exception SecurityException if a security manager exists and its
* <code>checkPropertyAccess</code> method doesn't allow
* access to the specified system property.
* @exception NullPointerException if <code>key</code> is
* <code>null</code>.
* @exception IllegalArgumentException if <code>key</code> is empty.
* @see #setProperty
* @see java.lang.SecurityException
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperties()
*/
public static String getProperty(String key) {
checkKey(key);
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPropertyAccess(key);
}
return props.getProperty(key);
}
/**
* Gets the system property indicated by the specified key.
* <p>
* First, if there is a security manager, its
* <code>checkPropertyAccess</code> method is called with the
* <code>key</code> as its argument.
* <p>
* If there is no current set of system properties, a set of system
* properties is first created and initialized in the same manner as
* for the <code>getProperties</code> method.
*
* @param key the name of the system property.
* @param def a default value.
* @return the string value of the system property,
* or the default value if there is no property with that key.
*
* @exception SecurityException if a security manager exists and its
* <code>checkPropertyAccess</code> method doesn't allow
* access to the specified system property.
* @exception NullPointerException if <code>key</code> is
* <code>null</code>.
* @exception IllegalArgumentException if <code>key</code> is empty.
* @see #setProperty
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperties()
*/
public static String getProperty(String key, String def) {
checkKey(key);
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPropertyAccess(key);
}
return props.getProperty(key, def);
}
/**
* 设置由指定键指示的系统属性。
* <p>
* 首先,如果存在安全管理器,则使用 <code>PropertyPermission(key, "write")</code> 权限调用其 <code>SecurityManager.checkPermission</code> 方法。
* 这可能导致 SecurityException 异常被抛出。如果没有抛出异常,则将指定的属性设置为给定值。
* <p>
*
* @param key 系统属性的名称。
* @param value 系统属性的值。
* @return 系统属性之前的值,如果它没有值,则返回 <code>null</code>。
*
* @exception SecurityException 如果存在安全管理器,并且其 <code>checkPermission</code> 方法不允许设置指定的属性。
* @exception NullPointerException 如果 <code>key</code> 或 <code>value</code> 为 <code>null</code>。
* @exception IllegalArgumentException 如果 <code>key</code> 是空字符串。
* @see #getProperty
* @see java.lang.System#getProperty(java.lang.String)
* @see java.lang.System#getProperty(java.lang.String, java.lang.String)
* @see java.util.PropertyPermission
* @see SecurityManager#checkPermission
* @since 1.2
*/
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);
}
/**
* 移除由指定键指示的系统属性。
* <p>
* 首先,如果存在安全管理器,则使用 <code>PropertyPermission(key, "write")</code> 权限调用其 <code>SecurityManager.checkPermission</code> 方法。
* 这可能导致 SecurityException 异常被抛出。如果没有抛出异常,则移除指定的属性。
* <p>
*
* @param key 要移除的系统属性的名称。
* @return 系统属性之前的字符串值,如果没有具有该键的属性,则返回 <code>null</code>。
*
* @exception SecurityException 如果存在安全管理器,并且其 <code>checkPropertyAccess</code> 方法不允许访问指定的系统属性。
* @exception NullPointerException 如果 <code>key</code> 为 <code>null</code>。
* @exception IllegalArgumentException 如果 <code>key</code> 是空字符串。
* @see #getProperty
* @see #setProperty
* @see java.util.Properties
* @see java.lang.SecurityException
* @see java.lang.SecurityManager#checkPropertiesAccess()
* @since 1.5
*/
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);
}
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");
}
}
/**
* 获取指定环境变量的值。环境变量是一个系统相关的外部命名值。
*
* <p>如果存在安全管理器,则使用 <code>{@link RuntimePermission}("getenv."+name)</code> 权限调用其 {@link SecurityManager#checkPermission checkPermission} 方法。
* 这可能导致 {@link SecurityException} 异常被抛出。如果没有抛出异常,则返回变量 <code>name</code> 的值。
*
* <p><a name="EnvironmentVSSystemProperties"><i>系统属性</i> 和 <i>环境变量</i></a> 都是从名称到值的映射。
* 这两种机制都可以用于将用户定义的信息传递给 Java 进程。环境变量具有更全局的影响,因为它们对定义它们的进程的所有后代可见,
* 而不仅仅是直接的 Java 子进程。它们在不同操作系统上可以具有略微不同的语义,例如大小写敏感性。因此,环境变量更容易产生意外的副作用。
* 最好尽可能使用系统属性。只有在需要全局影响或外部系统接口需要环境变量(如 <code>PATH</code>)时才应使用环境变量。
*
* <p>在 UNIX 系统上,名称的字母大小写通常是有意义的,而在 Microsoft Windows 系统上通常不是。
* 例如,表达式 <code>System.getenv("FOO").equals(System.getenv("foo"))</code> 在 Microsoft Windows 上可能为 true。
*
* @param name 环境变量的名称
* @return 变量的字符串值,如果变量在系统环境中未定义,则返回 <code>null</code>
* @throws NullPointerException 如果 <code>name</code> 为 <code>null</code>
* @throws SecurityException 如果存在安全管理器,并且其 {@link SecurityManager#checkPermission checkPermission} 方法不允许访问环境变量 <code>name</code>
* @see #getenv()
* @see ProcessBuilder#environment()
*/
public static String getenv(String name) {
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("getenv."+name));
}
return ProcessEnvironment.getenv(name);
}
/**
* 返回当前系统环境的一个不可修改的字符串映射视图。环境是一个从名称到值的系统相关映射,它会从父进程传递给子进程。
*
* <p>如果系统不支持环境变量,则返回一个空映射。
*
* <p>返回的映射将不包含 null 键或值。尝试查询 null 键或值的存在将抛出 {@link NullPointerException} 异常。
* 尝试查询类型不是 {@link String} 的键或值的存在将抛出 {@link ClassCastException} 异常。
*
* <p>返回的映射及其集合视图可能不遵守 {@link Object#equals} 和 {@link Object#hashCode} 方法的一般约定。
*
* <p>在所有平台上,返回的映射通常是区分大小写的。
*
* <p>如果存在安全管理器,则使用 <code>{@link RuntimePermission}("getenv.*")</code> 权限调用其 {@link SecurityManager#checkPermission checkPermission} 方法。
* 这可能导致 {@link SecurityException} 异常被抛出。
*
* <p>在向 Java 子进程传递信息时,通常优先使用<a href=#EnvironmentVSSystemProperties>系统属性</a>而不是环境变量。
*
* @return 作为变量名称到值的映射的环境
* @throws SecurityException 如果存在安全管理器,并且其 {@link SecurityManager#checkPermission checkPermission} 方法不允许访问进程环境
* @see #getenv(String)
* @see ProcessBuilder#environment()
* @since 1.5
*/
public static java.util.Map<String,String> getenv() {
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("getenv.*"));
}
return ProcessEnvironment.getenv();
}
/**
* 终止当前正在运行的 Java 虚拟机。参数用作状态码;按照惯例,非零状态码表示异常终止。
* <p>
* 此方法调用类 <code>Runtime</code> 中的 <code>exit</code> 方法。此方法不会正常返回。
* <p>
* 调用 <code>System.exit(n)</code> 等效于调用:
* <blockquote><pre>
* Runtime.getRuntime().exit(n)
* </pre></blockquote>
*
* @param status 退出状态。
* @throws SecurityException 如果存在安全管理器,并且其 <code>checkExit</code> 方法不允许以指定的状态退出。
* @see java.lang.Runtime#exit(int)
*/
public static void exit(int status) {
Runtime.getRuntime().exit(status);
}
/**
* 运行垃圾收集器。
* <p>
* 调用 <code>gc</code> 方法建议 Java 虚拟机尽力回收未使用的对象,以便使它们当前占用的内存可用于快速重用。
* 当从方法调用返回时,Java 虚拟机已经尽力从所有已弃用的对象中回收空间。
* <p>
* 调用 <code>System.gc()</code> 等效于调用:
* <blockquote><pre>
* Runtime.getRuntime().gc()
* </pre></blockquote>
*
* @see java.lang.Runtime#gc()
*/
public static void gc() {
Runtime.getRuntime().gc();
}
/**
* 运行任何待终结的对象的 finalization 方法。
* <p>
* 调用此方法表示 Java 虚拟机尽力运行那些被发现已被丢弃但其 finalization 方法尚未运行的对象的 <code>finalize</code> 方法。
* 当从方法调用返回时,Java 虚拟机已经尽力完成了所有未完成的 finalization。
* <p>
* 调用 <code>System.runFinalization()</code> 等效于调用:
* <blockquote><pre>
* Runtime.getRuntime().runFinalization()
* </pre></blockquote>
*
* @see java.lang.Runtime#runFinalization()
*/
public static void runFinalization() {
Runtime.getRuntime().runFinalization();
}
/**
* 启用或禁用退出时的终结操作;这样做指定在 Java 运行时退出之前将运行尚未自动调用的所有对象的终结器。
* 默认情况下,禁用退出时的终结操作。
*
* <p>如果存在安全管理器,
* 首先以 0 作为其参数调用其 <code>checkExit</code> 方法,以确保允许退出。
* 这可能导致 SecurityException 异常。
*
* @deprecated 此方法本质上是不安全的。它可能导致对活动对象的终结器被调用,同时其他线程同时操纵这些对象,导致异常行为或死锁。
* @param value 指示是否启用终结操作
* @throws SecurityException 如果存在安全管理器,并且其 <code>checkExit</code> 方法不允许退出。
*
* @see java.lang.Runtime#exit(int)
* @see java.lang.Runtime#gc()
* @see java.lang.SecurityManager#checkExit(int)
* @since JDK1.1
*/
@Deprecated
public static void runFinalizersOnExit(boolean value) {
Runtime.runFinalizersOnExit(value);
}
/**
* 加载指定文件名的本地库。文件名参数必须是绝对路径名。
*
* 如果文件名参数在去除平台特定库前缀、路径和文件扩展名时,指示一个静态链接到 VM 的本地库 L,
* 那么会调用由该库导出的 JNI_OnLoad_L 函数,而不是尝试加载动态库。
* 文件名与参数匹配的库不一定要存在于文件系统中。
* 更多细节请参阅 JNI 规范。
*
* 否则,文件名参数将以实现相关的方式映射到本地库映像。
*
* <p>
* 调用 <code>System.load(name)</code> 等效于调用:
* <blockquote><pre>
* Runtime.getRuntime().load(name)
* </pre></blockquote>
*
* @param filename 要加载的文件。
* @exception SecurityException 如果存在安全管理器,并且其 <code>checkLink</code> 方法不允许加载指定的动态库。
* @exception UnsatisfiedLinkError 如果文件名不是绝对路径名、本地库未与 VM 静态链接,或者主机系统无法将库映射为本地库映像。
* @exception NullPointerException 如果 <code>filename</code> 为 <code>null</code>。
* @see java.lang.Runtime#load(java.lang.String)
* @see java.lang.SecurityManager#checkLink(java.lang.String)
*/
@CallerSensitive
public static void load(String filename) {
Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
}
/**
* 加载指定的 <code>libname</code> 本地库。libname 参数不得包含任何平台特定的前缀、文件扩展名或路径。
* 如果名为 libname 的本地库与 VM 静态链接,那么将调用由该库导出的 JNI_OnLoad_libname 函数。
* 更多细节请参阅 JNI 规范。
*
* 否则,libname 参数将从系统库位置加载,并以实现相关的方式映射到本地库映像。
* <p>
* 调用 <code>System.loadLibrary(name)</code> 等效于调用
* <blockquote><pre>
* Runtime.getRuntime().loadLibrary(name)
* </pre></blockquote>
*
* @param libname 库的名称。
* @exception SecurityException 如果存在安全管理器,并且其 <code>checkLink</code> 方法不允许加载指定的动态库。
* @exception UnsatisfiedLinkError 如果 libname 参数包含文件路径、本地库未与 VM 静态链接,或者主机系统无法将库映射为本地库映像。
* @exception NullPointerException 如果 <code>libname</code> 为 <code>null</code>。
* @see java.lang.Runtime#loadLibrary(java.lang.String)
* @see java.lang.SecurityManager#checkLink(java.lang.String)
*/
@CallerSensitive
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
}
/**
* 将库名映射为表示本地库的平台特定字符串。
*
* @param libname 库的名称。
* @return 与平台相关的本地库名称。
* @exception NullPointerException 如果 <code>libname</code> 为 <code>null</code>。
* @see java.lang.System#loadLibrary(java.lang.String)
* @see java.lang.ClassLoader#findLibrary(java.lang.String)
* @since 1.2
*/
public static native String mapLibraryName(String libname);
/**
* 根据编码方式创建基于标准输出或标准错误的 PrintStream。
*/
private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
if (enc != null) {
try {
return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);
} catch (UnsupportedEncodingException uee) {}
}
return new PrintStream(new BufferedOutputStream(fos, 128), true);
}
/**
* 初始化系统类。在线程初始化后调用。
*/
private static void initializeSystemClass() {
// VM 可能会调用 JNU_NewStringPlatform() 来设置那些对编码敏感的属性(user.home、user.name、boot.class.path 等)
// 在 "props" 初始化期间,它可能需要通过 System.getProperty() 访问相关的系统编码属性,
// 这些属性在初始化早期(放入 "props")时已经被初始化。因此,确保在初始化的最开始处可用 "props" 并直接将所有系统属性放入其中。
props = new Properties();
initProperties(props); // 由 VM 初始化
// 有一些系统配置可能由 VM 选项控制,例如直接内存的最大量和用于支持自动装箱的对象标识语义的 Integer 缓存大小。
// 通常,库会从 VM 设置的属性中获取这些值。如果这些属性仅供内部实现使用,则应将这些属性从系统属性中删除。
//
// 例如,参考 java.lang.Integer.IntegerCache 和 sun.misc.VM.saveAndRemoveProperties 方法。
//
// 保存一个私有副本的系统属性对象,只能由内部实现访问。从中删除某些不适合公开访问的系统属性。
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")));
// 现在加载 zip 库,以防止 java.util.zip.ZipFile 尝试使用自身来加载此库。
loadLibrary("zip");
// 在 HUP、TERM 和 INT(如果可用)上设置 Java 信号处理程序。
Terminator.setup();
// 初始化需要为类库设置的任何其他操作系统设置。目前,在任何地方都是无操作,除了 Windows,
// 其中在使用 java.io 类之前设置了进程范围的错误模式。
sun.misc.VM.initializeOSEnvironment();
// 主线程不会像其他线程一样被添加到其线程组;我们必须在这里自己添加它。
Thread current = Thread.currentThread();
current.getThreadGroup().add(current);
// 注册共享秘密
setJavaLangAccess();
// 在初始化过程中调用子系统可以调用 sun.misc.VM.isBooted(),以避免做应该等待应用程序类加载器设置完毕的事情。
// 重要提示:确保这仍然是最后一个初始化操作!
sun.misc.VM.booted();
}
private static void setJavaLangAccess() {
// 允许 java.lang 之外的特权类
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
public sun.reflect.ConstantPool getConstantPool(Class<?> klass) {
return klass.getConstantPool();
}
public boolean casAnnotationType(Class<?> klass, AnnotationType oldType, AnnotationType newType) {
return klass.casAnnotationType(oldType, newType);
}
public AnnotationType getAnnotationType(Class<?> klass) {
return klass.getAnnotationType();
}
public Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap(Class<?> klass) {
return klass.getDeclaredAnnotationMap();
}
public byte[] getRawClassAnnotations(Class<?> klass) {
return klass.getRawAnnotations();
}
public byte[] getRawClassTypeAnnotations(Class<?> klass) {
return klass.getRawTypeAnnotations();
}
public byte[] getRawExecutableTypeAnnotations(Executable executable) {
return Class.getExecutableTypeAnnotationBytes(executable);
}
public <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared();
}
public void blockedOn(Thread t, Interruptible b) {
t.blockedOn(b);
}
public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) {
Shutdown.add(slot, registerShutdownInProgress, hook);
}
public int getStackTraceDepth(Throwable t) {
return t.getStackTraceDepth();
}
public StackTraceElement getStackTraceElement(Throwable t, int i) {
return t.getStackTraceElement(i);
}
public String newStringUnsafe(char[] chars) {
return new String(chars, true);
}
public Thread newThreadWithAcc(Runnable target, AccessControlContext acc) {
return new Thread(target, acc);
}
public void invokeFinalize(Object o) throws Throwable {
o.finalize();
}
});
}
}