绝大多数应用程序都需要一套持久保存的属性(property)来维护正常的运行。我们经常用Java.util包中的Properties类来实现这样的存储。它提供保存属性的一套方便使用的机制。但是有时候,你需要更复杂的属性文件结构,你可以通过扩展Properties类来达到这个目的。
Properities类按照“要害字——值”对的形式来保存数据,它不答应复制,但实际上,对复制功能的需求又是很常见的。不过,通过把同样的条目分成好几个文件并给不同要害字拷贝同样的值的方法,还是有可能用标准Properities类来达到拷贝的目的的。不幸的是,这个解决方法易于出错、而且更改起来也很单调乏味。一个简单的解决方法就是使用ProperitiesEXPansion类,它答应用“${}”标记来扩展属性来消除数据重复。它还答应你在同一个属性文件中使用同样的条目(通过把它们保存在不同的位置)。
扩展属性
属性扩展的首要目的就是使得属性文件中的数据表示更清楚更轻易维护。为了达到这个目的,你可以用“${}”标记来引入可被替换的参数,这样在运行时的属性查询时,它们可以扩展为用标记名所表示的值。下面是含有替换标记的属性文件的一个例子:
user.name=john
home.dir=usr
working.dir=${home.dir}/tmp
当访问这些属性时,“${home.dir}”标记就用“usr”值所代替,这样working.dir属性就是usr/tmp。请查看代码清单A所给出PropertiesExpansion类。为了提供标记扩展,我重载了标准Properties类的getProperty(String key)、setProperty(String key,String value)以及load(InputStream is),我还添加了replace()方法。
在清单A中有两个已重载的replace()方法,一个用来从当前属性清单中替换所有的替换标记,另一个repalce(String in,Hashtable keys)是一个方便的静态方法,它用包含替换标记的哈希表对象来执行同样的替换。
我们重写了setProperty()、load()和getProperty()方法,这样它就可以检查映射给定要害字的值是否包含扩展标记;假如发现扩展标记,它们就用合适的值来替换这些标记。
局部属性
在某些情况下,具有相同名字但映射为不同值的要害字是有用的。你可以通过局部(sectioning)属性文件来达到这个目的,如下所示:
# global properties
section.root=root
x1=2
y1=0
[user.1]
x1=${x1}
y1=10
[${section.root}]
x1=123
y2=20
在“user.1”之上的所有“要害字——值”对是全局参数,在程序不同的地方都可以引用这些全局参数来实现值替换。例如,在属性扩展之后,${section.root}区域就变成了“root”区域,而属性x1在user.1区域的值为2。
假如你需要从指定区域中查询一个已命名属性,那么你可以使用getProperty(String section,String key)方法。它把区域名作为一个附加参数。每个区域名都映射到一个包含“要害字——值”对的Properties对象。为了在user.1区域内得到x1属性的值,请用下面的一行代码执行清单B中的代码:
PropertiesExpansion.getProperty(“user.1”,”x1”)
清单B中的setProperty()方法用来为期望的区域设置“要害字——值”对。该方法调用哈希表的put()方法,该方法由PropertiesExpansion类所重载。Put()方法的诀窍在于判定一个“要害字——值”对属于哪个区域并相应更新该区域。由于put()方法答应插入其要害字或者值不是字符串的条目,所以我强烈希望你不要直接用put()方法来设置属性。
你可以通过调用sections()方法来查询所有的区域的名字,该方法返回区域名字的枚举类型。属于某个区域的所有要害字可以通过调用sectionKeys()方法来查找到。为了利用区域的位置把属性写道文件之中,store()方法被重载了。
还有诸如getInt()、getLong()、getFloat()、getDouble()和getBoolean()等附加的方法,它们用来简化把属性值的类型转换为诸如整型、长整型、浮点型、双精度和布尔等的简单数据类型。这些方法的参数为包含给定要害字的值的附加Properties对象。