当前位置: 首页 > 科技观察

Properties的简单分析

时间:2023-03-13 15:59:46 科技观察

最近在看java集合的源码时,发现由于我们经常使用的Properties类继承自Hashtable!我又长知识了!01.摘要在集合系列的第一章中,我们了解到了Map的实现类,包括HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties等。在上一章中,我们介绍了Hashtable的数据结构和算法实现。在Java中其实有一个很重要的类Properties,它继承自Hashtable,主要用来读取配置文件。本文通过看JDK的博客和一些网友总结,主要介绍Properties的使用实例。如有理解不当之处,敬请指正。02.简介Properties类是java工具包中一个非常重要的类。比如在实际开发中,我们可以直接在自定义的java枚举类中写入一些变量。但是有些变量在测试环境、预生产环境和生产环境中需要不同的值。这时候我们可以通过properties文件加载程序需要的配置信息,实现一行代码多环境。都可以工作!最常见的是JDBC数据源配置文件。属性文件以.properties为后缀。文件内容以key=value格式写入。左边是变量名,右边是变量值。使用#作为注释,比如新建一个jdbc.properties文件,内容如下:Properties类是properties文件和程序之间的中间桥梁,无论是从properties文件中读取信息还是写入信息到属性文件,它必须通过Properties类。好了,唠叨了这么多,还是回到本文要介绍的主角属性吧!从集合Map架构图中可以看出,Properties继承自Hashtable,即持久化的Map集合,属性列表以key-value的形式存在。Properties类定义如下:publicclassPropertiesextendsHashtable{...}PropertiesProperties除了继承Hashtable中定义的方法外,还定义了如下常用方法,如图:常用方法介绍set方法(添加和修改元素)set方法是将指定的键值对添加到map中。添加元素时,会调用Hashtable的put方法。与Hashtable不同,key和value都是字符串。打开Properties的setProperty方法,源码如下:publicsynchronizedObjectsetProperty(Stringkey,Stringvalue){//调用父类Hashtable的put方法returnput(key,value);}方法测试如下:publicstaticvoidmain(String[]args){Propertiesproperties=newProperties();properties.setProperty("name1","张三");properties.setProperty("name2","张4");properties.setProperty("name3","张三")");System.out.println(properties.toString());}输出结果:{name3=张武,name2=张四,name1=张三}get方法(搜索指定元素)get方法返回对应根据指定的key值取值,第一步是从调用Hashtable的get方法,如果有返回值,直接返回;如果没有返回值,但是初始化时传入了defaults变量,则从defaults变量即Properties中查找是否有对应的变量,如果有则返回元素值。打开Properties的getProperty方法,源码如下:publicStringgetProperty(Stringkey){//调用父类的get方法HashtableObjectoval=super.get(key);Stringsval=(ovalinstanceofString)?(String)oval:null;//变量为空判断return((sval==null)&&(defaults!=null))?defaults.getProperty(key):sval;}查看defaults变量,源码如下:publicclassPropertiesextendsHashtable{protectedPropertiesdefaults;}这个变量在赋值的时候,打开源码如下:你给一个自定义的defaults,在调用Hashtable的get方法时,没有找到元素值,而且defaults不等于空,那么会在defaults中进一步查找元素值。方法测试如下:publicstaticvoidmain(String[]args){Propertiesproperties=newProperties();properties.setProperty("name1","张三");properties.setProperty("name2","张四");properties.setProperty("name3","张武");//将属性初始化为newProperties作为参数keySystem.out.println("queryresult:"+properties.getProperty("name1"));}outputresult:queryresultbykey:张三加载方法(加载配置文件)加载方法,即属性文件将输入为流的形式加载文件,提取里面的键值对,将键值对元素添加到map中。打开Properties的load方法,源码如下:publicsynchronizedvoidload(InputStreaminStream)throwsIOException{//读取文件流load0(newLineReader(inStream));}load0方法,源码如下:privatevoidload0(LineReaderlr)throwsIOException{char[]convtBuf=newchar[1024];intlimit;intkeyLen;intvalueStart;charc;booleanhasSep;booleanprecedingBackslash;//逐行读取while((limit=lr.readLine())>=0){c=0;keyLen=0;valueStart=limit;hasSep=false;precedingBackslash=false;//判断key的长度while(keyLenpropertyNames(){Hashtableh=newHashtable<>();//将原图添加到新的Hashtableenumerate(h);//返回Hashtable中的所有关键元素returnh.keys();}enumerate方法,源码如下:privatesynchronizedvoidenumerate(Hashtableh){//判断Properties中是否有初始化的配置文件if(defaults!=null){defaults.enumerate(h);}//将原Hashtable中的数据添加到新的Hashtable中for(Enumeratione=keys();e.hasMoreElements();){Stringkey=(String)e.nextElement();h.put(key,get(key));}}方法测试如下:publicstaticvoidmain(String[]args)throwsException{//初始化PropertiesPropertiesprop=newProperties();//加载配置文件InputStreamin=TestProperties.class.getClassLoader().getResourceAsStream("custom.properties");//读取配置文件,指定读取编码UTF-8,防止content乱码prop.load(newInputStreamReader(in,"UTF-8"));//获取属性Enumeration中的所有关键元素enProp=prop.propertyNames();while(enProp.hasMoreElements()){Stringkey=(String)enProp.nextElement();Stringvalue=prop.getProperty(key);System.out.println(key+"="+value);}}输出如下:userPwd=123456userEmail=123@123.comuserAge=18userName=李三userGender=male总结继承自Hashtable的属性,大部分方法在Hashtable中是复用的,比如get、put、remove、clear方法。**与Hashtable的区别在于Properties中的key和value都是字符串。**如果需要获取properties中的所有内容,可以先通过iterator或者propertyNames方法获取map中的所有key元素,然后遍历获取key和value。需要注意的是Properties中的setProperty和load方法都添加了synchronized同步锁来控制线程同步。03.properties文件的加载方式在实际开发中,经常会遇到读取配置文件的路径找不到,或者读取的文件内容是乱码的情况。下面简单介绍几种常用的properties文件的加载方式。属性加载文件的方式大致可以分为两类。第一类是使用java.util.Properties的load方法加载文件流;第二类是使用java.util.ResourceBundle类来获取文件内容。在src/recources目录中,创建一个新的custom.properties配置文件。文件编码格式为UTF-8。内容还是以刚才的测试为例。加载方法如下!通过文件路径加载文件。就是调用Properties的load方法,获取文件路径,读取文件,以流的形式加载文件。方法如下:Propertiesprop=newProperties();//获取文件的绝对路径StringfilePath="/coding/java/src/resources/custom.properties";//加载配置文件InputStreamin=newFileInputStream(newFile(filePath));//读取配置文件prop.load(newInputStreamReader(in,"UTF-8"));System.out.println("用户名:"+prop.getProperty("用户名"));输出结果:userName:李三通过当前类的loader的getResourceAsStream方法获取到该类型的方法来加载文件,同时也调用了Properties的load方法。不同的是文件路径是通过类加载器获取的。如果当前文件在src/resources目录下,那么直接传入文件名,OK。方法如下:Propertiesprop=newProperties();//加载配置文件InputStreamin=TestProperties.class.getClassLoader().getResourceAsStream("custom.properties");//读取配置文件prop.load(newInputStreamReader(in,"UTF-8"));System.out.println("用户名:"+prop.getProperty("用户名"));输出结果:userName:李三使用ClassLoader类的getSystemResourceAsStream方法获取与上面类似,也是通过类加载器获取文件流,方法如下:Propertiesprop=newProperties();//加载配置文件InputStreamin=ClassLoader.getSystemResourceAsStream("custom.properties");//读取配置文件prop.load(newInputStreamReader(in,"UTF-8"));System.out.println("userName:"+prop.getProperty("用户名"));输出结果:userName:李三使用ResourceBundle类加载文件。ResourceBundle类加载文件,与Properties不同,ResourceBundle获取properties文件不需要加.properties后缀,只需要文件名即可。ResourceBundle按照iso8859编码格式读取原始属性文件。如果是阅读中文内容,需要转码。方法如下://加载自定义配置文件,无需添加`.properties`后缀名ResourceBundleresource=ResourceBundle.getBundle("custom");//转码处理,解决中文内容阅读乱码问题Stringvalue=newString(resource.getString("userName").getBytes("ISO-8859-1"),"UTF-8");System.out.println("userName:"+value);outputresult:userName:LiSan04.源码总结从上面可以看出Properties继承自Hashtable,Hashtable中复用了大部分方法。与Hashtable不同的是,Properties中的键和值都是字符串。在实际开发中,Properties主要用于读取配置文件,尤其是在不同的环境下需要变量值不同。通过读取配置文件可以避免在java枚举类中写入变量值。从而达到一行代码运行多处的目的!读取Properties配置文件时,很容易因为找不到文件路径而报错。您可以参考几种加载属性文件的方法。