JDK源码分析--Properties源码分析

注:

        以下分析基于JDK1.8.0_74。

 

一、概述

        1、Properties类表示一组持久属性。属性列表中的每个键及其对应值都是一个字符串。

       2、可以将属性内容写出到stream中或者从stream中读取属性内容。

       3、Properties类继承自Hashtable,是线程安全的类,即多个线程可以共享一个Properties对象,而不需要外部同步。

       4、Hashtable的所有方法Properties对象均可以访问。

       5、Properties支持文本方式和xml方式的数据存储。

       (1)在文本方式中,格式为key:value,其中分隔符可以是:冒号(:)、等号(=)、空格。其中空格可以作为key的结束,同时获取的值回将分割符号两端的空格去掉。

       (2)XML属性文档具有以下DOCTYPE声明:

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

注意,导出或导入属性时不访问系统URI (http://java.sun.com/dtd/properties.dtd);它只是作为一个字符串来唯一标识DTD

XML例如:

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<properties>

<comment>comments</comment>

<entry key="key1">value1</entry>

<entry key="key2">value2</entry>

<entry key="key3">value3</entry>

</properties>

       6、Properties只支持1对1模式的属性设置,而且不支持多层多级属性设置。

 

二、他爹

1、继承Hashtable<Object,Object>

       Hashtable可以理解为线程安全的HashMap,它们都实现了Map接口,内部实现几乎一样。

Hashtable与HashMap的不同点有以下几个:

       (1)Hashtable是线程安全的,方法都使用了synchronized修饰。

但这里值得一提的是,平时在使用线程安全的Map时,并不推荐使用Hashtable,因为其方法使用的同步锁(对象锁,对当前实例加锁),并发执行效率较低;在Java5以后,提供了ConcurrentHashMap,可替代Hashtable的功能,或使用Collections.synchronizedMap((Map<K,V> m)方法获得线程安全的SynchronizedMap类。(ConcurrentHashMap使用的是锁分段技术,可有效提高并发访问效率,具体请自行百度;推荐使用该类达到线程安全的目的

       (2)HashMap使用的迭代器(Iterator)是fail-fast迭代器,Hashtable的迭代器(Enumerator)不是fail-fast的。

:fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。

       (3)HashMap可以使用null键和值,而Hashtable的键和值都不能为null。

      以put(K key, V value)方法为例:

public synchronized V put(K key, V value) {
    // Make sure the value is not null
    if (value == null) {
        throw new NullPointerException();
    }
    // Makes sure the key is not already in the hashtable.
    Entry<?,?> tab[] = table;
    int hash = key.hashCode();
   ……
    return null;
}

       该方法判断value为null时会抛出NullPointerException,而执行后面的语句key.hashCode()时,如果key为null也会抛出NullPointerException。

2、不建议的继承方法

JDK1.8帮助文档中提到:

        因为属性继承自Hashtable,所以put和putAll方法可以应用于Properties对象。强烈反对使用它们,因为它们允许调用者插入键或值不是字符串的条目。应该使用setProperty方法。如果在包含非字符串键或值的“受损”Properties对象上调用store或save方法,则调用将失败。类似地,如果对包含非字符串键的“受影响的”Properties对象调用propertyNames或list方法,则调用将失败。

 

二、重要属性

protected Properties defaults;

        除了继承于Hashtable的属性,Properties仅有这一个属性。其作用在JDK1.8帮助文档中解释为:

“属性列表可以包含另一个属性列表作为其“默认值”;如果在原始属性列表中没有找到属性键,则搜索第二个属性列表。”

       1、默认值的初始化:通过带参数的构造方法对其进行赋值。

       2、默认值的使用:

主要使用在方法getProperty(String key),通过key获取value。即 “当原始属性列表中没有找到属性键时,搜索此默认属性列表”。

public String getProperty(String key) {
    Object oval = super.get(key);
    String sval = (oval instanceof String) ? (String)oval : null;
 return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}

 

三、构造方法

       1、无参构造方法

public Properties() {
    this(null);
}

       2、设置默认Properties值的构造方法

public Properties(Properties defaults) {
    this.defaults = defaults;
}

 

四、常用方法

1、getProperty(String key)

       通过键获取值,如果列表中无值,再从默认Properties属性中获取值。

public String getProperty(String key) {
    Object oval = super.get(key);
    String sval = (oval instanceof String) ? (String)oval : null;
 return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}

2、getProperty(String key, String defaultValue)

       通过键获取值,如果无值返回入参的值。

public String getProperty(String key, String defaultValue) {
    String val = getProperty(key);
    return (val == null) ? defaultValue : val;
}

3、load(InputStream inStream)

       从字节流中加载key/value键值对,要求所有的key/value键值对是按行存储,同时是ISO-8859-1编码。

public synchronized void load(InputStream inStream) throws IOException {
    load0(new LineReader(inStream));
}

private void load0 (LineReader lr) throws IOException {
   ……
    String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
    String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
    put(key, value);
}

4、load(Reader reader)

       从字符流中加载key/value键值对,要求所有的键值对都是按照行来存储的。

public synchronized void load(Reader reader) throws IOException {
    load0(new LineReader(reader));
}

load0方法同上。

5、loadFromXML(InputStream in)

       从xml文件中加载property,Java7底层使用XMLUtils.load(Properties,InputStream)方法来加载;Java8对这个方法做了修改,以下源码为Java8;XML默认情况下使用UTF-8字符编码。

public synchronized void loadFromXML(InputStream in)
    throws IOException, InvalidPropertiesFormatException{
    XmlSupport.load(this, Objects.requireNonNull(in));
    in.close();
}
private static final XmlPropertiesProvider PROVIDER = loadProvider();
static void load(Properties props, InputStream in)
    throws IOException, InvalidPropertiesFormatException{
    PROVIDER.load(props, in);
}

loadProvider()方法返回的是抽象类XmlPropertiesProvider的一个实现类BasicXmlPropertiesProvider,底层通过其ParserSAX来实现XML数据加载。

6、store(Writer writer, String comments)

       将所有的property(保存defaults的)都写出到字符流中,如果给定comments的话,则可在输入设置上添加注释。

public void store(Writer writer, String comments)
        throws IOException{
    store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
                                             : new BufferedWriter(writer),
           comments,
           false);
}

7、store(OutputStream out, String comments)

       将所有的property(保存defaults的)都写出到字节流中,默认ISO-8859-1编码,如果给定comments的话,则可在输入设置上添加注释。

public void store(OutputStream out, String comments)
        throws IOException{
    store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
           comments,
           true);
}

8、storeToXML(OutputStream os, String comment, String encoding)

       数据写入到xml文件中。

public void storeToXML(OutputStream os, String comment, String encoding)
        throws IOException{
    XmlSupport.save(this, Objects.requireNonNull(os), comment,
                    Objects.requireNonNull(encoding));
}

public void storeToXML(OutputStream os, String comment)
        throws IOException{
    storeToXML(os, comment, "UTF-8");
}

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值