Java 中文官方教程 2022 版(十)(1)https://developer.aliyun.com/article/1486347
首先,应用程序设置一个默认的Properties
对象。该对象包含一组属性,如果在其他地方没有明确设置值,则使用这些属性。然后,load 方法从名为defaultProperties
的磁盘上的文件中读取默认值。
接下来,应用程序使用不同的构造函数创建第二个Properties
对象applicationProps
,其默认值包含在defaultProps
中。当检索属性时,默认值起作用。如果在applicationProps
中找不到属性,则会搜索其默认列表。
最后,代码从名为appProperties
的文件中将一组属性加载到applicationProps
中。该文件中的属性是上次调用应用程序时保存的属性,如下一节所述。
保存属性
以下示例使用Properties.store
从前一个示例中写出应用程序属性。默认属性不需要每次保存,因为它们永远不会更改。
FileOutputStream out = new FileOutputStream("appProperties"); applicationProps.store(out, "---No Comment---"); out.close();
store
方法需要一个要写入的流,以及一个字符串,该字符串用作输出顶部的注释。
获取属性信息
一旦应用程序设置了其Properties
对象,应用程序可以查询该对象以获取有关其包含的各种键和值的信息。应用程序在启动后从Properties
对象获取信息,以便根据用户的选择初始化自身。Properties
类有几种获取属性信息的方法:
contains(Object value)
和containsKey(Object key)
如果值或键在Properties
对象中,则返回true
。Properties
从Hashtable
继承这些方法。因此,它们接受Object
参数,但只应使用String
值。getProperty(String key)
和getProperty(String key, String default)
返回指定属性的值。第二个版本提供默认值。如果找不到键,则返回默认值。list(PrintStream s)
和list(PrintWriter w)
将所有属性写入指定的流或写入器。这对于调试很有用。elements()
,keys()
和propertyNames()
返回一个包含Properties
对象中包含的键或值(如方法名所示)的枚举。keys
方法仅返回对象本身的键;propertyNames
方法还返回默认属性的键。stringPropertyNames()
类似于propertyNames
,但返回一个Set
,并且仅返回键和值都是字符串的属性名称。请注意,Set
对象不由Properties
对象支持,因此对其中一个对象的更改不会影响另一个对象。size()
返回当前键/值对的数量。
设置属性
用户在应用程序执行期间与应用程序的交互可能会影响属性设置。这些更改应该反映在Properties
对象中,以便在应用程序退出时(并调用store
方法时)保存这些更改。以下方法更改Properties
对象中的属性:
setProperty(String key, String value)
将键/值对放入Properties
对象中。remove(Object key)
删除与键关联的键/值对。
注意: 上述描述的一些方法在Hashtable
中定义,因此接受除String
之外的键和值参数类型。始终使用String
作为键和值,即使该方法允许其他类型。同时不要在Properties
对象上调用Hashtable.set
或Hastable.setAll
;始终使用Properties.setProperty
。
命令行参数
原文:
docs.oracle.com/javase/tutorial/essential/environment/cmdLineArgs.html
一个 Java 应用程序可以从命令行接受任意数量的参数。这允许用户在启动应用程序时指定配置信息。
用户在调用应用程序时输入命令行参数,并在要运行的类名后指定这些参数。例如,假设一个名为Sort
的 Java 应用程序对文件中的行进行排序。要对名为friends.txt
的文件中的数据进行排序,用户会输入:
java Sort friends.txt
当一个应用程序启动时,运行时系统会通过一个String
数组将命令行参数传递给应用程序的主方法。在前面的示例中,传递给Sort
应用程序的命令行参数是包含一个单独String
的数组:"friends.txt"
。
回显命令行参数
Echo
示例会将每个命令行参数单独显示在一行上:
public class Echo { public static void main (String[] args) { for (String s: args) { System.out.println(s); } } }
以下示例展示了用户如何运行Echo
。用户输入以斜体显示。
*java Echo Drink Hot Java* Drink Hot Java
请注意,应用程序会将每个单词 — Drink
、Hot
和 Java
— 单独显示在一行上。这是因为空格字符分隔命令行参数。要将Drink
、Hot
和Java
解释为单个参数,用户应该用引号将它们括起来。
*java Echo "Drink Hot Java"* Drink Hot Java
解析数值型命令行参数
如果一个应用程序需要支持一个表示数字的命令行参数,它必须将代表数字的String
参数(如"34")转换为数值。以下是一个将命令行参数转换为int
的代码片段:
int firstArg; if (args.length > 0) { try { firstArg = Integer.parseInt(args[0]); } catch (NumberFormatException e) { System.err.println("Argument" + args[0] + " must be an integer."); System.exit(1); } }
如果parseInt
的args[0]
的格式无效,会抛出NumberFormatException
。所有的Number
类 — Integer
、Float
、Double
等等 — 都有parseXXX
方法,将代表数字的String
转换为其类型的对象。
环境变量
原文:
docs.oracle.com/javase/tutorial/essential/environment/env.html
许多操作系统使用环境变量将配置信息传递给应用程序。与 Java 平台中的属性类似,环境变量是键/值对,其中键和值都是字符串。设置和使用环境变量的约定在操作系统之间以及命令行解释器之间有所不同。要了解如何在您的系统上将环境变量传递给应用程序,请参考系统文档。
查询环境变量
在 Java 平台上,应用程序使用System.getenv
来检索环境变量的值。没有参数时,getenv
返回一个只读的java.util.Map
实例,其中映射键是环境变量名称,映射值是环境变量值。这在EnvMap
示例中有所展示:
import java.util.Map; public class EnvMap { public static void main (String[] args) { Map<String, String> env = System.getenv(); for (String envName : env.keySet()) { System.out.format("%s=%s%n", envName, env.get(envName)); } } }
使用String
参数,getenv
返回指定变量的值。如果未定义变量,则getenv
返回null
。Env
示例以这种方式使用getenv
来查询在命令行上指定的特定环境变量:
public class Env { public static void main (String[] args) { for (String env: args) { String value = System.getenv(env); if (value != null) { System.out.format("%s=%s%n", env, value); } else { System.out.format("%s is" + " not assigned.%n", env); } } } }
将环境变量传递给新进程
当 Java 应用程序使用ProcessBuilder
对象创建新进程时,传递给新进程的默认环境变量集合与提供给应用程序的虚拟机进程的集合相同。应用程序可以使用ProcessBuilder.environment
更改此集合。
平台依赖性问题
不同系统上实现环境变量的方式之间存在许多微妙的差异。例如,Windows 在环境变量名称中忽略大小写,而 UNIX 则不会。环境变量的使用方式也各不相同。例如,Windows 在名为USERNAME
的环境变量中提供用户名,而 UNIX 实现可能在USER
、LOGNAME
或两者中提供用户名。
为了最大化可移植性,在系统属性中提供相同值时,永远不要引用环境变量。例如,如果操作系统提供用户名,则始终可以在系统属性user.name
中找到。
其他配置实用程序
原文:
docs.oracle.com/javase/tutorial/essential/environment/other.html
这里是一些其他配置实用程序的摘要。
首选项 API允许应用程序在一个与实现相关的后备存储中存储和检索配置数据。支持异步更新,并且同一组首选项可以被多个线程甚至多个应用程序安全地更新。更多信息,请参考首选项 API 指南。
部署在JAR 归档中的应用程序使用清单来描述归档的内容。更多信息,请参考在 JAR 文件中打包程序课程。
Java Web Start 应用程序的配置包含在一个JNLP 文件中。更多信息,请参考 Java Web Start 课程。
Java 插件小程序的配置部分取决于用于在网页中嵌入小程序的 HTML 标签。根据小程序和浏览器,这些标签可以包括、
、
和
。更多信息,请参考 Java 小程序课程。
类
java.util.ServiceLoader
提供了一个简单的服务提供者设施。服务提供者是服务的实现—一组众所周知的接口和(通常是抽象的)类。服务提供者的类通常实现服务中定义的接口并子类化类。服务提供者可以作为扩展安装(参见扩展机制)。提供者也可以通过将它们添加到类路径或通过其他特定于平台的方式来提供。
系统工具
系统工具
原文:
docs.oracle.com/javase/tutorial/essential/environment/system.html
System
类实现了许多系统工具。其中一些已经在之前关于配置工具的部分中介绍过。本节介绍其他一些系统工具。
命令行 I/O 对象
命令行 I/O 对象
原文:
docs.oracle.com/javase/tutorial/essential/environment/cl.html
System
提供了几个预定义的 I/O 对象,这些对象在一个旨在从命令行启动的 Java 应用程序中非常有用。这些对象实现了大多数操作系统提供的标准 I/O 流,还有一个对于输入密码很有用的控制台对象。更多信息,请参考从命令行进行 I/O 在 基本 I/O 课程中。
系统属性
系统属性
原文:
docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
在 Properties 中,我们研究了应用程序如何使用
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 供应商名称 |
"java.vendor.url" |
JRE 供应商 URL |
"java.version" |
JRE 版本号 |
"line.separator" |
操作系统用于在文本文件中分隔行的序列 |
"os.arch" |
操作系统架构 |
"os.name" |
操作系统名称 |
"os.version" |
操作系统版本 |
"path.separator" |
java.class.path 中使用的路径分隔符字符 |
"user.dir" |
用户工作目录 |
"user.home" |
用户主目录 |
"user.name" |
用户账户名 |
安全注意事项: 访问系统属性可能受到 安全管理器 的限制。这在小程序中最常见,小程序被阻止读取某些系统属性,并且无法写入任何系统属性。有关在小程序中访问系统属性的更多信息,请参阅 System Properties 中的 Java 富互联网应用程序进阶 课程。
读取系统属性
读取系统属性
System
类有两个用于读取系统属性的方法:getProperty
和 getProperties
。
System
类有两个不同版本的 getProperty
。两者都检索参数列表中命名的属性的值。其中较简单的 getProperty
方法接受一个参数,即属性键。例如,要获取 path.separator
的值,请使用以下语句:
System.getProperty("path.separator");
getProperty
方法返回一个包含属性值的字符串。如果属性不存在,此版本的 getProperty
返回 null。
getProperty
的另一个版本需要两个 String
参数:第一个参数是要查找的键,第二个参数是在找不到键或键没有值时要返回的默认值。例如,下面的 getProperty
调用查找名为 subliminal.message
的 System
属性。这不是一个有效的系统属性,所以该方法返回提供的第二个参数作为默认值:“购买 StayPuft 棉花糖!
”
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 解释器。运行时系统每次启动时都会重新初始化系统属性。如果要使系统属性的更改持久化,则应用程序必须在退出之前将值写入某个文件,并在启动时重新读取。
安全管理器
安全管理器
原文:
docs.oracle.com/javase/tutorial/essential/environment/security.html
安全管理器是为应用程序定义安全策略的对象。该策略指定了不安全或敏感的操作。安全策略不允许的任何操作都会导致抛出
SecurityException
。应用程序还可以查询其安全管理器以发现哪些操作是允许的。
通常,Web 小程序在浏览器或 Java Web Start 插件提供的安全管理器下运行。其他类型的应用程序通常在没有安全管理器的情况下运行,除非应用程序本身定义了一个。如果没有安全管理器存在,应用程序就没有安全策略,并且可以无限制地运行。
本节解释了应用程序如何与现有安全管理器交互。有关更详细的信息,包括如何设计安全管理器的信息,请参考安全指南。
与安全管理器交互
与安全管理器交互
安全管理器是
SecurityManager
类型的对象;要获取对此对象的引用,请调用System.getSecurityManager
。
SecurityManager appsm = System.getSecurityManager();
如果没有安全管理器,则此方法返回
null
。
一旦应用程序有了安全管理器对象的引用,它可以请求执行特定操作的权限。标准库中的许多类都会这样做。例如,
System.exit
用于终止具有退出状态的 Java 虚拟机,会调用SecurityManager.checkExit
来确保当前线程有权限关闭应用程序。
SecurityManager 类定义了许多其他方法,用于验证其他类型的操作。例如,
SecurityManager.checkAccess
验证线程访问,SecurityManager.checkPropertyAccess
验证对指定属性的访问。每个操作或操作组都有自己的check*XXX*()
方法。
此外,
check*XXX*()
方法集表示已受安全管理器保护的操作集。通常,应用程序不必直接调用任何check*XXX*()
方法。
识别安全违规
识别安全违规
许多在没有安全管理器的情况下是例行操作的操作,在有安全管理器的情况下可能会抛出
SecurityException
。即使调用一个没有记录为抛出SecurityException
的方法也是如此。例如,考虑以下用于写入文件的代码:
reader = new FileWriter("xanadu.txt");
在没有安全管理器的情况下,此语句执行时不会出错,前提是
xanadu.txt
存在且可写。但假设此语句插入到一个通常在不允许文件输出的安全管理器下运行的 Web 小程序中。可能会导致以下错误消息:
*appletviewer fileApplet.html* Exception in thread "AWT-EventQueue-1" java.security.AccessControlException: access denied (java.io.FilePermission xanadu.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 中的其他方法
System 中的其他方法
原文:
docs.oracle.com/javase/tutorial/essential/environment/sysmisc.html
本节描述了一些在前几节中未涵盖的
System
中的方法。
arrayCopy
方法有效地在数组之间复制数据。有关更多信息,请参考 Arrays 中的 Language Basics 课程。
currentTimeMillis
和 nanoTime
方法在应用程序执行期间测量时间间隔很有用。要测量毫秒级时间间隔,需要在间隔开始和结束时分别调用currentTimeMillis
,并将第一个返回值从第二个返回值中减去。类似地,连续调用nanoTime
可以测量纳秒级时间间隔。
注意:
currentTimeMillis
和 nanoTime
的准确性受操作系统提供的时间服务限制。不要假设currentTimeMillis
精确到最近的毫秒,也不要假设nanoTime
精确到最近的纳秒。此外,既不应该使用currentTimeMillis
也不应该使用nanoTime
来确定当前时间。应使用高级方法,如java.util.Calendar.getInstance
。
exit
方法导致 Java 虚拟机关闭,退出状态由参数指定。退出状态可供启动应用程序的进程使用。按照惯例,退出状态为0
表示应用程序正常终止,而其他任何值都是错误代码。
PATH 和 CLASSPATH
PATH 和 CLASSPATH
原文:
docs.oracle.com/javase/tutorial/essential/environment/paths.html
本节解释了如何在 Microsoft Windows、Solaris 和 Linux 上使用
PATH
和CLASSPATH
环境变量。请查阅随 Java 开发工具包(JDK)软件包安装包含的安装说明以获取最新信息。
安装软件后,JDK 目录将具有如下结构。
bin
目录包含编译器和启动器。
更新 PATH 环境变量(Microsoft Windows)
更新 PATH 环境变量(Microsoft Windows)
没有设置
PATH
环境变量也可以正常运行 Java 应用程序。或者,您可以选择性地设置它以方便使用。
如果要方便地从任何目录运行可执行文件(
javac.exe
、java.exe
、javadoc.exe
等),而不必键入命令的完整路径,则设置PATH
环境变量。如果不设置PATH
变量,每次运行时都需要指定可执行文件的完整路径,例如:
C:\Java\jdk1.7.0\bin\javac MyClass.java
PATH
环境变量是一系列由分号(;
)分隔的目录。Microsoft Windows 按照从左到右的顺序在PATH
目录中查找程序。每次只能在路径中有一个 JDK 的bin
目录(第一个之后的将被忽略),因此如果已经存在一个,可以更新该特定条目。
以下是一个
PATH
环境变量的示例:
C:\Java\jdk1.7.0\bin;C:\Windows\System32\;C:\Windows\;C:\Windows\System32\Wbem
将
PATH
环境变量永久设置是有用的,这样在重新启动后它将保留。要对PATH
变量进行永久更改,请使用控制面板中的系统图标。具体的操作步骤因 Windows 版本而异:
Windows XP
选择开始,选择控制面板。双击系统,选择高级选项卡。
点击环境变量。在系统变量部分,找到
PATH
环境变量并选择它。点击编辑。如果PATH
环境变量不存在,点击新建
。在编辑系统变量(或新建系统变量)窗口中,指定
PATH
环境变量的值。点击确定。通过点击确定关闭所有剩余窗口。
Windows Vista:
从桌面上右键单击我的电脑图标。
从上下文菜单中选择属性。
点击高级选项卡(在 Vista 中点击高级系统设置链接)。
点击环境变量。在系统变量部分,找到
PATH
环境变量并选择它。点击编辑。如果PATH
环境变量不存在,点击新建
。在编辑系统变量(或新建系统变量)窗口中,指定
PATH
环境变量的值。点击确定。通过点击确定关闭所有剩余窗口。
Windows 7:
从桌面上右键单击计算机图标。
从上下文菜单中选择属性。
点击高级系统设置链接。
点击环境变量。在系统变量部分,找到
PATH
环境变量并选择它。点击编辑。如果PATH
环境变量不存在,点击新建
。在编辑系统变量(或新建系统变量)窗口中,指定
PATH
环境变量的值。点击确定。通过点击确定关闭所有剩余窗口。
**注意:**在从控制面板编辑
PATH
环境变量时,可能会看到类似以下内容的环境变量:
%JAVA_HOME%\bin;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem
用百分号(
%
)括起来的变量是现有的环境变量。如果这些变量中的一个在控制面板的环境变量窗口中列出(如JAVA_HOME
),则可以编辑其值。如果未显示,则是操作系统定义的特殊环境变量。例如,SystemRoot
是 Microsoft Windows 系统文件夹的位置。要获取环境变量的值,请在命令提示符下输入以下内容。(此示例获取SystemRoot
环境变量的值):
echo %SystemRoot%
更新 PATH 变量(Solaris 和 Linux)
更新 PATH 变量(Solaris 和 Linux)
您可以很好地运行 JDK 而不设置
PATH
变量,或者可以选择设置它作为便利。但是,如果要能够从任何目录运行可执行文件(javac
、java
、javadoc
等),而不必键入命令的完整路径,则应该设置路径变量。如果不设置PATH
变量,每次运行时都需要指定可执行文件的完整路径,例如:
% /usr/local/jdk1.7.0/bin/javac MyClass.java
要查看路径是否正确设置,请执行:
% java -version
如果可以找到,这将打印
java
工具的版本。如果版本过旧或者出现错误java: Command not found,则路径未正确设置。
要永久设置路径,请在启动文件中设置路径。
对于 C shell(
csh
),编辑启动文件(~/.cshrc
):
set path=(/usr/local/jdk1.7.0/bin $path)
对于
bash
,编辑启动文件(~/.bashrc
):
PATH=/usr/local/jdk1.7.0/bin:$PATH export PATH
对于
ksh
,启动文件由环境变量ENV
命名。要设置路径:
PATH=/usr/local/jdk1.7.0/bin:$PATH export PATH
对于
sh
,编辑配置文件(~/.profile
):
PATH=/usr/local/jdk1.7.0/bin:$PATH export PATH
然后加载启动文件,并通过重复
java
命令验证路径是否设置:
对于 C shell(
csh
):
% source ~/.cshrc % java -version
对于
ksh
、bash
或sh
:
% . /.profile % java -version
Java 中文官方教程 2022 版(十)(3)https://developer.aliyun.com/article/1486350