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 == '\t' || 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 != '\t' && 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;
}
}

四、结果测试

Properties类按顺序输出加载内容的更多相关文章

  1. Java 类中各成分加载顺序 和 内存中的存放位置

    参加一个笔试,有一个关于类的静态代码块.构造代码块.构造函数的执行顺序的问题.不太清楚,网上百度了一下.在这里记录一下. 一.什么时候会加载类?使用到类中的内容时加载:有三种情况1.创建对象:new ...

  2. Java笔记(十二)……类中各部分加载顺序及存放位置问题

    什么时候会加载类 使用到类中的内容时加载,三种情况: 创建对象:new StaticDemo(); 使用类中的静态成员:StaticCode.num = 9;  StaticCode.getNum() ...

  3. struts2:struts.properties配置文件介绍及常量加载顺序

    1. 背景 struts2框架中有两个核心配置文件,其中struts.xml文件主要负责管理应用中的action映射,以及该action包含的result定义等.除此之外,struts2框架还包括一个 ...

  4. java类的编译、加载和执行

    一.java类的编译流程 这里主要讲的是从java文件到class文件 下图是java类编译的详细步骤: 1.词法分析:将java源代码的字符流转变为标记(Token)的集合,Token是编译过程中的 ...

  5. java类到底是如何加载并初始化的?

    Java虚拟机如何把编译好的.class文件加载到虚拟机里面?加载之后如何初始化类?静态类变量和实例类变量的初始化过程是否相同,分别是如何初始化的呢?这篇文章就 是解决上面3个问题的. 若有不正之处, ...

  6. (转)java类到底是如何加载并初始化的?

    Java虚拟机如何把编译好的.class文件加载到虚拟机里面?加载之后如何初始化类?静态类变量和实例类变量的初始化过程是否相同,分别是如何初始化的呢?这篇文章就 是解决上面3个问题的. 若有不正之处, ...

  7. Win8 Metro动态加载内容框架

    制作背景 为了参加ImagineCup 2013 世界公民类比赛,我们设计制作了一个可动态扩展的幼教类App.这个App需要能动态加载内容,内容包括带动画可交互的电子书,动画,视频,游戏. 技术支持 ...

  8. js 利用 ajax 加载 js ,显示加载进度 ,严格按照js的顺序先后加载到页面

    js 利用 ajax 加载 js ,显示加载进度 ,严格按照js的顺序先后加载到页面 , 做手机端开发时,发现一个问题,有些浏览器,在网速比较慢的情况下,js文件没有加载完,后续的调用已经开始调用了, ...

  9. Java虚拟机——类的结构与加载

    1.为什么Java可以跨平台 因为有java虚拟机,跨平台是因为字节码即class文件具有平台无关性,java代码会经过java虚拟机转换为字节码 2.class文件的结构 class文件主要是以8位 ...

随机推荐

  1. 04webpack--webpack-dev-server 时时跟新

    <!-- 如何添加npm run dev 启动程序 下载npm i webpack-dev-server -S 在pack.json中添加 "dev": "webp ...

  2. UML类图基础说明

    UML类图主要由类和关系组成. 类: 什么具有相同特征的对象的抽象, 具体我也记不住, 反正有官方定义 关系: 指各个类之间的关系 类图 类就使用一个方框来表示, 把方框分成几层, 来表示不同的信息, ...

  3. 12Java基础_数组定义格式/动态初始化/静态初始化

    /* Java数组 格式一: int[] array; 格式二: int array[]; 数组初始化: 为数组中的元素分配内存空间 动态初始化: int[] array=new int[数组长度] ...

  4. while语句 break和continue

    1.whlie 循环 基本条件 :while 条件: 代码块(循环体) else: 当上面的条件为假的,才会执行 执行顺序: 判断条件是否为真,如果为真,执行循环体,然后判断条件,...直到循环条件为 ...

  5. Python基础之猜数游戏

    例题一:猜数游戏.在程序中预设一个0~9之间的整数,让用户通过键盘输入所猜的数,如果大于预设的数,显示“遗憾,太大了”:小于预设的数,显示“遗憾,太小了”,如此循环,直至猜中该数,显示“预测N次,你猜 ...

  6. xLua 学习

    xLua https://github.com/Tencent/xLua 文档 https://tencent.github.io/xLua/public/v1/guide/index.html FA ...

  7. android shape图形优化Button效果

    android shape可以让我们通过定义xml文件的方式创建图形,当然只能实现一些比较简单的图形(圆形,矩形,椭圆,线段),但是已经相当不错了,通过shape创建的图形作为控件的背景已经基本可以满 ...

  8. phpize安装PHP扩展

    安装编译完成php源码后忘记安装一些扩展可以通过phpize来安装 拿lnmp1.6安装举例 安装完成lnmp后发现有些扩展没有 lnmp1.6的安装脚本会在lnmp1.6里生成src,里面是lnmp ...

  9. vscode自定义vue模板代码

    File--->preference -->user Snippets-->搜索html.json 编辑 加入以下自定义代码内容 "Html5-Vue": { & ...

  10. (二十三)golang--内置函数

    1.用于求长度,占多少个字节 2.内置函数new:分配内存,主要用来分配值类型,比如int.float等,其第一个实参为类型,而非值,其返回值为指向该类型的新分配的零值的指针: 3.make:用来分配 ...