◆通常狀況下,咱們都使用相對路徑來獲取資源,這樣的靈活性比較大.java
好比當前類爲com/ketqi/Test.class
而圖像資源好比sample.gif應該放置在com/ketqi/sample.gif
而若是這些圖像資源放置在icons目錄下,則應該是com/ketqi/icons/sample.gif
經過當前類文件的路徑獲取資源主要有以下幾種方式:
· 假設當前類爲com.ketqi.Test
· 包所在的文件夾爲bin
String p_w_picpathName = "icons/sample.gif"
1, 經過Class.getResource()定位類路徑下的資源(bin/com/ketqi/icons/sample.gif)
Class clazz = this.getClass();
URL url = clazz.getResource(p_w_picpathName);
2,經過ClassLoader.getResource()定位包的根目錄下的資源(bin/icons/sample.gif)
Class clazz = this.getClass();
URLClassLoader loader = (URLClassLoader)clazz.getClassLoader();
URL url = loader.getResource(p_w_picpathName);
3, 經過ClassLoader.findResource()提供本身定製的方式定位資源
URL url = loader.findResource(p_w_picpathName);
◆那麼這三種方法有那些區別, 咱們應該在什麼時候使用哪一種方法呢?
· Class.getResource() 方法
該方法實際經過該Class的Class Loader的getResource()方法來得到資源, 在調用ClassLoader的getResource()方法以前, Class.getResource()方法會對資源名稱作必定的處理,構建一個該資源的絕對名稱(absolute name, 大意是:若是資源名稱以'/'('"u002f') 開始, 則資源的絕對名稱是'/'之後的部分. 若是p_w_picpathName是"/icons/sample.gif", 則在這裏會變成"icons/sample.gif"+不然對於其餘狀況, 絕對名稱將是以下形式(給資源名稱的前面加上modified_package_name/): modified_package_name/resource_name (修正的包名稱/資源名稱)
其中修正的包名稱含義是將當前對象所在的包名稱中的'.'('"u002e')替換爲'/'若是ClassLoader.getResource()方法返回一個值爲null的URL, 則Class.getResource()方法最終會將資源請求交給ClassLoader.getSystemResource(java.lang.String).
· ClassLoader.getResource() 方法該對資源進行查找, 資源的名稱是以'/'分隔的路徑, 這個方法首先查找本身的父親ClassLoader, 由本身的父ClassLoader來查找資源(實際上, 若是父親的父親不是空, 則父親仍會向上提交查找請求). 若是本身的父ClassLoader是null, 則查找Java虛擬機中內建的class loader, 並將資源請求提交給它們, 若是這些操做都失敗了, 則ClassLoader會調用本身的findResource()方法來查找資源.
· ClassLoader.findResource() 方法該方法在內部查找指定的資源, 若是你實現了本身的Class Loader,則應該重載這個方法以本身特定的方式來查找類文件和資源.
◆經過以上的總結, 咱們能夠看到三點.
1, 不管是getResource(), 仍是findResource(), 這些方法都只是資源的定位方法, 最終都只是返回一個URL, 只是對資源的定位而已, 咱們隨後應經過本身的方法來讀取這些資源. 而在Class和ClassLoader中還定義的有getResourceAsStream方法, 該方法是getResource的加強版, 這裏就不介紹了.
2,若是須要以類爲相對路徑查找資源, 則應該調用Class.getResource()方法, 不要直接調用
ClassLoader.getResource()方法. 另外, 除非是你本身定義了ClassLoader並重載了findResource方法,不然也不要直接調用ClassLoader.findResource方法, 由於在Class.getResource()方法中會對資源名稱做必定的處理, 這在上面介紹了, 下面舉個實例: 假設個人當前類在intellij工程Database下, 類所在的包是com.ketqi.test, 而icons目錄放在bin/com/ketqi/test/目錄下, 我須要獲得icons/sample.gif文件的URL, 則調用this.getClass().getResource()獲得的URL是: file:/E:/projects/intellij/bin/com/ketqi/test/icons/sample.gif
3, 有時候咱們但願某個jar庫的圖像資源在同一個icons下統一管理, 而不是爲每一個包下面的Class建一個icons, 也就是說須要以庫爲相對路徑來查找資源, 此時則應該調用ClassLoader.getResource()方法, 舉個例子:
·某個工程有以下的包結構:
com.ketqi.other
com.ketqi.test
com.ketqi.database
·若是以類爲相對路徑, 則在每一個包下都必須創建一個icons目錄, 並放置相應的資源文件. 以下:
com.ketqi.other/icons/...
com.ketqi.test/icons/...
com.ketqi.database/icons/...
·而咱們可能但願在根目錄下放置一個icons目錄, 把全部資源放置在這裏管理, 這樣還能夠防止資源的重複.
就是以下形式
com.ketqi.other
com.ketqi.test
com.ketqi.database
icons/sample.gif ...
則此時咱們應該調用ClassLoader.getResource方法, 因爲它沒有對資源名稱做處理, 也就是說沒有將修正的包名添加到資源名稱前, 因此它會在類所在的包的根下去查找資源.(運行java程序的語法是java com.ketqi.other.Test, 因此根目錄是com目錄的上級目錄).