• Properties类按顺序输出加载内容


    Properties类按顺序输出加载内容

    最近手写工厂的时候,遇到了加载配置文件时不按照properties文件中的数据的顺序来加载。

    一、问题代码

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    
    public class PropertiesTest {
        public static void main(String[] args) {
            InputStream ips = null;
            try {
                ips = Properties.class.getResourceAsStream("/test.properities");
                Properties props = new Properties();
                props.load(ips);
                for(String name:props.stringPropertyNames())
                    System.out.println(props.getProperty(name) + " "+name);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if(ips != null){
                        ips.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    
    

    配置文件

    cat=1
    dog=2
    bird=3
    mouse=4
    pig=5
    

    输出结果

    二、原因分析

    public class Properties extends Hashtable<Object,Object>
    

    上面是Properties类的定义,可以看到它继承了Hashtable类

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

    load方法调用load0方法

    private void load0 (LineReader lr) throws IOException {
            char[] convtBuf = new char[1024];
            int limit;
            int keyLen;
            int valueStart;
            char c;
            boolean hasSep;
            boolean precedingBackslash;
    
            while ((limit = lr.readLine()) >= 0) {
                c = 0;
                keyLen = 0;
                valueStart = limit;
                hasSep = false;
    
                //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
                precedingBackslash = false;
                while (keyLen < limit) {
                    c = lr.lineBuf[keyLen];
                    //need check if escaped.
                    if ((c == '=' ||  c == ':') && !precedingBackslash) {
                        valueStart = keyLen + 1;
                        hasSep = true;
                        break;
                    } 
                    else if ((c == ' ' || c == '	' ||  c == 'f') && !precedingBackslash) 					{
                        valueStart = keyLen + 1;
                        break;
                    }
                    if (c == '\') {
                        precedingBackslash = !precedingBackslash;
                    } else {
                        precedingBackslash = false;
                    }
                    keyLen++;
                }
                while (valueStart < limit) {
                    c = lr.lineBuf[valueStart];
                    if (c != ' ' && c != '	' &&  c != 'f') {
                        if (!hasSep && (c == '=' ||  c == ':')) {
                            hasSep = true;
                        } else {
                            break;
                        }
                    }
                    valueStart++;
                }
                String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
                String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
                put(key, value);
            }
        }
    

    load0方法可以看到最后取到key和value值后会调用父类Hashtable的put()方法,把数据存入Hashtable,具体的Hashtable源码这里就不再贴出。简单来说Hashtable的put()方法接收到值后会按照哈希值存储,而不是按照读取顺序存储。

    接下来是读取时的源码,有兴趣的可以看一下:

    public Set<String> stringPropertyNames() {
            Hashtable<String, String> h = new Hashtable<>();
            enumerateStringProperties(h);
            return h.keySet();
        }
    

    enumerateStringProperties方法:

    private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
            if (defaults != null) {
                defaults.enumerateStringProperties(h);
            }
            for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
                Object k = e.nextElement();
                Object v = get(k);
                if (k instanceof String && v instanceof String) {
                    h.put((String) k, (String) v);
                }
            }
        }
    

    Hashtable的keySet()方法

    public Set<K> keySet() {
            if (keySet == null)
                keySet = Collections.synchronizedSet(new KeySet(), this);
            return keySet;
        }
    

    三、解决方法

    写一个工具类继承Properties类,实现以下功能:

    1. 创建一个能够按照读取顺序来存储properities文件中的key值的集合框架
    2. 能够返回步骤1创建的集合

    在这里我采用了LinkedList来顺序存储key值(也可以采用别的集合类型),然后重写put方法,先把值存入自己建的LinkedList中,再调用父类的方法。关于返回Key值的集合是新写了一个orderStringPropertyNames()方法返回LinkedList

    实现代码如下:

    import java.util.LinkedList;
    import java.util.Properties;
    
    public class LinkedProperities extends Properties {
    
        private LinkedList<String> linkedList = new LinkedList<String>();
    
    
    
        @Override
        public synchronized Object put(Object key, Object value) {
            linkedList.add((String) key);
            return super.put(key, value);
        }
    
    
        public LinkedList<String> orderStringPropertyNames() {
            return linkedList;
        }
    }
    
    

    四、结果测试

  • 相关阅读:
    YbSoftwareFactory 代码生成插件【二十】:DynamicObject的序列化
    YbSoftwareFactory 代码生成插件【十九】:实体类配合数据库表字段进行属性扩展的小技巧
    YbSoftwareFactory 代码生成插件【十八】:树形结构下的查询排序的数据库设计
    YbSoftwareFactory 代码生成插件【十七】:先进的权限模型体系设计
    YbSoftwareFactory 代码生成插件【十六】:Web 下灵活、强大的审批流程实现(含流程控制组件、流程设计器和表单设计器)
    YbSoftwareFactory 代码生成插件【十五】:Show 一下最新的动态属性扩展功能与键值生成器功能
    YbSoftwareFactory 代码生成插件【十四】:通过 DynamicLinq 简单实现 N-Tier 部署下的服务端数据库通用分页
    YbSoftwareFactory 代码生成插件【十三】:Web API 的安全性
    Navicat 密码加密算法
    GitHub开源的超棒后台管理面板
  • 原文地址:https://www.cnblogs.com/ys1109/p/11382190.html
Copyright © 2020-2023  润新知