系统实用工具
System类实现了许多系统实用程序,其中一些已在上一节配置实用程序中介绍过,本节介绍一些其他系统实用程序。
命令行I/O对象
系统提供了几个预定义的I/O对象,这些对象在Java应用程序中非常有用,可以从命令行启动,它们实现了大多数操作系统提供的标准I/O流,以及用于输入密码的控制台对象,有关更多信息,请参阅基础I/O课程中的命令行I/O。
系统属性
在属性中,我们研究了应用程序可以使用Properties
对象来维护其配置的方式,Java平台本身使用Properties
对象来维护自己的配置,System
类维护一个Properties
对象,该对象描述当前工作环境的配置,系统属性包括有关当前用户、Java运行时的当前版本以及用于分隔文件路径名的组件的字符的信息。
下表描述了一些最重要的系统属性。
键 | 含义 |
---|---|
"file.separator" | 用于分隔文件路径组件的字符,这在UNIX上是“/”,在Windows上是“\” |
"java.class.path" | 用于查找包含类文件的目录和JAR存档的路径,类路径的元素由path.separator 属性中指定的特定于平台的字符分隔 |
"java.home" | Java Runtime Environment(JRE)的安装目录 |
"java.vendor" | JRE vendor名称 |
"java.vendor.url" | JRE vendor URL |
"java.version" | JRE版本号 |
"line.separator" | 操作系统用于分隔文本文件中的行的序列 |
"os.arch" | 操作系统架构 |
"os.name" | 操作系统名称 |
"path.separator" |
java.class.path 中使用的路径分隔符 |
"user.dir" | 用户工作目录 |
"user.home" | 用户主目录 |
"user.name" | 用户帐户名称 |
安全考虑:安全管理器可以限制对系统属性的访问,这通常是applet中的一个问题,它无法读取某些系统属性,也无法写入任何系统属性,有关访问applet中的系统属性的更多信息,请参阅“使用Java Rich Internet Applications进行更多操作”课程中的“系统属性”。
读取系统属性
System
类有两个用于读取系统属性的方法:getProperty
和getProperties
。
System
类有两个不同版本的getProperty
,两者都检索参数列表中指定的属性的值,两个getProperty
方法中较简单的方法是使用单个参数,即属性键。例如,要获取path.separator
的值,请使用以下语句:
System.getProperty("path.separator");
getProperty
方法返回包含属性值的字符串,如果该属性不存在,则此版本的getProperty
返回null
。
另一个版本的getProperty
需要两个String
参数:第一个参数是查找的键,如果无法找到键或没有值,则第二个参数是要返回的默认值。例如,以下对getProperty
的调用会查找名为subliminal.message
的System
属性,这不是有效的系统属性,因此该方法不是返回null
,而是返回作为第二个参数提供的默认值:"Buy StayPuft Marshmallows!"。
System.getProperty("subliminal.message", "Buy StayPuft Marshmallows!");
System
类提供的访问属性值的最后一个方法是getProperties
方法,该方法返回一个Properties对象,该对象包含一组完整的系统属性定义。
写入系统属性
要修改现有的系统属性集,请使用System.setProperties
,此方法采用已初始化为包含要设置的属性的Properties
对象,此方法使用Properties
对象表示的新集替换整个系统属性集。
更改系统属性可能存在危险,应谨慎处理,许多系统属性在启动后不会重新读取,而是用于提供信息,更改某些属性可能会产生意外的副作用。
下一个示例PropertiesTest创建一个Properties
对象,并从myProperties.txt初始化它。
subliminal.message=Buy StayPuft Marshmallows!
然后,PropertiesTest
使用System.setProperties
将新的Properties
对象安装为当前的系统属性集。
import java.io.FileInputStream;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args)
throws Exception {
// set up new properties object
// from file "myProperties.txt"
FileInputStream propFile =
new FileInputStream( "myProperties.txt");
Properties p =
new Properties(System.getProperties());
p.load(propFile);
// set the system properties
System.setProperties(p);
// display new properties
System.getProperties().list(System.out);
}
}
注意PropertiesTest
如何创建Properties
对象p
,它被用作setProperties
的参数:
Properties p = new Properties(System.getProperties());
此语句使用当前系统属性集初始化新属性对象p
,在此小应用程序的情况下,该属性是由运行时系统初始化的属性集。然后,应用程序从文件myProperties.txt
将其他属性加载到p
中,并将系统属性设置为p
。这具有将myProperties.txt
中列出的属性添加到运行时系统在启动时创建的属性集的效果,请注意,应用程序可以创建没有任何默认Properties
对象的p
,如下所示:
Properties p = new Properties();
另请注意,系统属性的值可以被覆盖!例如,如果myProperties.txt
包含以下行,则将覆盖java.vendor
系统属性:
java.vendor=Acme Software Company
通常,请注意不要覆盖系统属性。
setProperties
方法更改当前正在运行的应用程序的系统属性集,这些变化并不持久。也就是说,更改应用程序中的系统属性不会影响将来对此解释程序或任何其他应用程序的Java解释程序的调用,运行时系统每次启动时都会重新初始化系统属性,如果要保持对系统属性的更改,则应用程序必须在退出之前将值写入某个文件,并在启动时再次读取它们。
安全管理器
安全管理器是定义应用程序安全策略的对象,此策略指定不安全或敏感的操作,安全策略不允许的任何操作都会导致抛出SecurityException,应用程序还可以查询其安全管理器以发现允许的操作。
通常,Web applet与浏览器或Java Web Start插件提供的安全管理器一起运行,其他类型的应用程序通常在没有安全管理器的情况下运行,除非应用程序本身定义了安全管理器。如果没有安全管理器,则该应用程序没有安全策略,并且没有任何限制。
本节介绍应用程序如何与现有安全管理器进行交互,有关更多详细信息,包括有关如何设计安全管理器的信息,请参阅安全指南。
与安全管理器交互
安全管理器是SecurityManager类型的对象,要获取对此对象的引用,请调用System.getSecurityManager
。
SecurityManager appsm = System.getSecurityManager();
如果没有安全管理器,则此方法返回null
。
一旦应用程序具有对安全管理器对象的引用,它就可以请求执行特定事务的权限,标准库中的许多类都是这样做的。例如,以退出状态终止Java虚拟机的System.exit
调用SecurityManager.checkExit
以确保当前线程具有关闭应用程序的权限。
SecurityManager
类定义了许多用于验证其他类型操作的其他方法。例如,SecurityManager.checkAccess
验证线程访问,SecurityManager.checkPropertyAccess
验证对指定属性的访问,每个操作或一组操作都有自己的checkXXX()
方法。
此外,checkXXX()
方法集表示已受安全管理器保护的操作集,通常,应用程序不必直接调用任何checkXXX()
方法。
确认安全违规
在没有安全管理器的情况下,许多常规操作在使用安全管理器运行时都会抛出SecurityException
,即使在调用未记录为抛出SecurityException
的方法时也是如此,例如,请考虑以下用于读取文件的代码:
reader = new FileReader("xanadu.txt");
在缺少安全管理器的情况下,如果xanadu.txt
存在且可读,则此语句无错误地执行,但是假设此语句插入到Web applet中,该applet通常在不允许文件输入的安全管理器下运行,可能会导致以下错误消息:
appletviewer fileApplet.html
Exception in thread "AWT-EventQueue-1" java.security.AccessControlException: access denied (java.io.FilePermission characteroutput.txt write)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkWrite(SecurityManager.java:962)
at java.io.FileOutputStream.<init>(FileOutputStream.java:169)
at java.io.FileOutputStream.<init>(FileOutputStream.java:70)
at java.io.FileWriter.<init>(FileWriter.java:46)
...
请注意,在这种情况下抛出的特定异常java.security.AccessControlException是SecurityException
的子类。
系统中的其他方法
本节介绍了前面几节中未介绍的System
中的一些方法。
arrayCopy
方法有效地在数组之间复制数据,有关更多信息,请参阅语言基础知识课程中的数组。
currentTimeMillis和nanoTime方法可用于测量应用程序执行期间的时间间隔。要以毫秒为单位测量时间间隔,请在间隔的开始和结束时调用currentTimeMillis
两次,并从第二个返回值中减去第一个值。同样,调用nanoTime
两次测量一个纳秒的间隔。
currentTimeMillis
和nanoTime
的准确性受操作系统提供的时间服务的限制,不要假设currentTimeMillis
精确到最接近的毫秒,或者nanoTime
精确到最接近的纳秒。此外,currentTimeMillis
和nanoTime
都不应用于确定当前时间,使用高级方法,例如java.util.Calendar.getInstance。
exit方法使Java虚拟机关闭,并使用参数指定的整数退出状态,退出状态可用于启动应用程序的进程,按照惯例,退出状态为0表示应用程序正常终止,而任何其他值都是错误代码。、
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。