用類加載器的5中形式讀取.properties文件(這個(gè).properties文件一般放在src的下面)
創(chuàng)新互聯(lián)成立于2013年,先為晉中等服務(wù)建站,晉中等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為晉中企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
用類加載器進(jìn)行讀?。哼@里采取先向大家講讀取類加載器的幾種方法;然后寫一個(gè)例子把幾種方法融進(jìn)去,讓大家直觀感受。最后分析原理。(主要是結(jié)合所牽涉的方法的源代碼的角度進(jìn)行分析)
這里先介紹用類加載器讀取的幾種方法:
1.任意類名.class.getResourceAsStream("/文件所在的位置");【文件所在的位置從包名開始寫】
2.和.properties文件在同一個(gè)目錄下的類名.class.getResourceAsStream("文件所在的位置");【文件所在的位置從包名開始寫,注意這里和上面的相比較少了一個(gè)斜杠/】
當(dāng)然你也可以寫成跟1一樣的形式即:任意類名.class.getResourceAsStream("/文件所在的位置");
3.任意類名.class.getClassLoader().getResourceAsStream("文件所在的位置");【文件所在的位置從包名開始寫】
4.任意類名.class.getClassLoader().getResource("文件所在的位置").openStream();【文件所在的位置從包名開始寫】
5.任意類名.class.getClassLoader().getResource("文件所在的位置")..openConnection().getInputStream();【文件所在的位置從包名開始寫】
//一個(gè)例子,說明上述5中方法的用法。
上面圖片中的各個(gè)紅色矩形就是我要讀取的properties文件。主要是兩類。一類直接放在src下面。另一類是放在某個(gè)文件夾下面.
//f.properties文件的內(nèi)容如下圖所示;
//上述五種情況說明的代碼如下:
package com.qls.commonclass; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import com.qls.counter.Ok; /** * 分別用類加載器的5種方法讀取f.properties文件。 * @author 秦林森 * */ public class Test6 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub /**第一種情形獲取輸入流。 * 任意類名.class.getResourceAsStream("/文件所在的位置");【文件所在的位置從包名開始寫】 * @param args */ //獲取輸入流 InputStream in = Test.class.getResourceAsStream("/com/qls/counter/f.properties"); /** * 第二種情形獲取輸入流。 * 和.properties文件在同一個(gè)目錄下的類名.class.getResourceAsStream("文件所在的位置"); * 【文件所在的位置從包名開始寫,注意這里和上面的相比較少了一個(gè)斜杠/】 * 這里隨便選擇一個(gè)與:f.properties在同一個(gè)目錄下的類比如Ok這個(gè)類吧! * 這里你自然也可以寫成跟第一種情況一樣的形式: * 即: * InputStream in2 = Ok.class.getResourceAsStream("/com/qls/counter/f.properties"); * 因?yàn)榈谝环N情況是針對(duì)任意一個(gè)類而言的公式。 */ InputStream in2 = Ok.class.getResourceAsStream("f.properties"); /** * 第三種情形獲取輸入流: * 任意類名.class.getClassLoader().getResourceAsStream("文件所在的位置"); * 【文件所在的位置從包名開始寫】 */ InputStream in3 = Test2.class.getClassLoader().getResourceAsStream("com/qls/counter/f.properties"); /** * 第四中情形獲取輸入流: * 任意類名.class.getClassLoader().getResource("文件所在的位置").openStream(); * 【文件所在的位置從包名開始寫】 */ InputStream in4 = Test4.class.getClassLoader().getResource("com/qls/counter/f.properties").openStream(); /** * 第五種情形獲取輸入流: * .任意類名.class.getClassLoader().getResource("文件所在的位置").openConnection().getInputStream(); * 【文件所在的位置從包名開始寫】 */ InputStream in5 = Test5.class.getClassLoader().getResource("com/qls/counter/f.properties").openConnection().getInputStream(); //創(chuàng)建Properties Properties prop=new Properties(); //把輸入流in加載到prop中 /* * 驗(yàn)證上述5中輸入流是否成立。只需帶入prop.load(InputStream inputStream);驗(yàn)證即可。 * 也就是: * prop.load(in); * prop.load(in2); * prop.load(in3); * prop.load(in4); * prop.load(in5); */ prop.load(in5); System.out.println("sixi="+prop.getProperty("sixi")); System.out.println("ouyangfeng="+prop.getProperty("ouyangfeng")); System.out.println("rape="+prop.getProperty("farm")); } }/* Output: sixi=river ouyangfeng=masses farm=flower **///:~
上述5中方法的原理分析。
首先看看Class中的resolveName(String name)究竟是干什么的。源碼如下所示:
private String resolveName(String name) { if (name == null) { return name; } if (!name.startsWith("/")) { Class<?> c = this; while (c.isArray()) { c = c.getComponentType(); } String baseName = c.getName(); int index = baseName.lastIndexOf('.'); if (index != -1) { name = baseName.substring(0, index).replace('.', '/') +"/"+name; } } else { name = name.substring(1); } return name; }
下面我把這個(gè)源碼講的內(nèi)容翻譯人類語言:
給任意一個(gè)字符串name,如果該name是以/開始的,則該函數(shù)返回的是:去掉/這個(gè)字符的字符串。(如name="/ouyangfeng" 則調(diào)用該函數(shù)之后得到的結(jié)果是:name=ouyangfeng)。
如果該name這個(gè)字符串不是以/開始的,則該函數(shù)返回的結(jié)果是調(diào)用這個(gè)函數(shù)類所在的包名+name組成的字符串(例如假設(shè)Test5所在的包名是:com.qls.mount 。則:Test5.class.resolveName("ouyangfeng");返回結(jié)果是:com/qls/mount/ouyangfeng)
也就是幫助文檔講述的:
If the name
begins with a '/'
('\u002f'), then the absolute name of the resource is the portion of the name
following the '/'
.
Otherwise, the absolute name is of the following form:modified_package_name/name
Where the modified_package_name
is the package name of this object with '/'
substituted for '.'
('\u002e').
上述英文我簡(jiǎn)要翻譯一下:如果name是以一個(gè)/開頭,則這個(gè)資源的絕對(duì)name就是:name中/之后的部分內(nèi)容。
否則:這這個(gè)絕對(duì)name就是如下形式。包名/name,把這里包名中的.用/代替掉?!救纾篶om.qls.river把.用/代替掉就是:com/qls/river】
然后我們?cè)倏纯碈lass類中的getResourceAsStream(String name)的源碼和ClassLoader中的getResourceAsStream(String name)中的源碼。
Class類中的getResourceAsStream(String name)的源碼如下:
public InputStream getResourceAsStream(String name) { name = resolveName(name);//注意這里有一個(gè)resolveName(String name)方法,根據(jù)上述的分析,易知道這個(gè)源碼的意思. ClassLoader cl = getClassLoader0(); if (cl==null) { // A system class. return ClassLoader.getSystemResourceAsStream(name); } return cl.getResourceAsStream(name); }
ClassLoader中的getResourceAsStream(String name)中的源碼如下:
public InputStream getResourceAsStream(String name) { URL url = getResource(name); try { return url != null ? url.openStream() : null;//這句代碼的意思是:如果url不是null時(shí)返回的是:url.openStream(),反之如果url為null則返回null. } catch (IOException e) { return null; } }
通過這Class.resolveName(String name)中的源代碼和ClassLoader.getResourceAsStream(String name)中的源代碼以及Class.getResourceAsStream(String name)中的原代碼我們易知道上述五種情況是怎么來的。無需記憶。
只需學(xué)會(huì)數(shù)學(xué)推理即可。
大家在看源碼是:發(fā)現(xiàn)Class.resolveName(String name)這個(gè)方法是private的,你用普通方法根本調(diào)用不了,下面我順便提一下:如何調(diào)用這個(gè)方法。以便大家可以更好的理解這個(gè)方法所講的意思。
package com.qls.commonclass; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 用反射調(diào)用ClassLoade中的 private String resolveName(String name) * 驗(yàn)證這個(gè)方法所講的意思。 * @author 秦林森 * */ public class Test7 { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub //得到這個(gè)方法。 Method method = Class.class.getDeclaredMethod("resolveName", new Class[]{String.class}); //由于這個(gè)方法是private,所以要獲取這個(gè)方法的訪問權(quán)限 method.setAccessible(true); //寫一個(gè)實(shí)例,以便調(diào)用這個(gè)方法。 Object obj = Test7.class;//Test這個(gè)類所在的包是:com.qls.commonclass //調(diào)用這個(gè)方法 String invoke = (String) method.invoke(obj, new Object[]{"ouyangfeng"}); String invoke2 = (String) method.invoke(obj, new Object[]{"/ouyangfeng"}); System.out.println("invoke="+invoke); System.out.println("invoke2="+invoke2); } }/* Output: invoke=com/qls/commonclass/ouyangfeng invoke2=ouyangfeng 由此可以證明了:以/開頭的字符串"/ouyangfeng"調(diào)用resolveName(String name) 這個(gè)方法之后返回的結(jié)果是:ouyangfeng 不以/開頭的字符串:"ouyangfeng"返回的結(jié)果是:調(diào)用這個(gè)方法的包名/name 【在本例中是Test7調(diào)用resolveName(String name),而Test7所在的包是:com.qls.commonclass 所以返回結(jié)果是:com/qls/commonclass/ouyangfeng】 *///:~
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。