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