国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Java 正確地從類(lèi)路徑中獲取資源

發(fā)布時(shí)間:2021-07-05 18:40 來(lái)源:腳本之家 閱讀:0 作者:Chen-Zhiqiang 欄目: 開(kāi)發(fā)技術(shù)

目錄

Java 可通過(guò)以下幾種方法來(lái)訪(fǎng)問(wèn)資源:

  • Class 的 getResource 方法
  • ClassLoader 的 getResource 方法
  • ClassLoader 的 getSystemResource 靜態(tài)方法

在使用中,Class 可通過(guò)直接引用類(lèi)的 class 屬性而獲得,或是通過(guò)實(shí)例的 getClass() 方法來(lái)獲得。獲取 ClassLoader 的方式則比較多,常見(jiàn)以下幾種:

  • 調用 Class 的 getClassLoader 方法,如:getClass().getClassLoader()
  • 由當前線(xiàn)程獲取 ClassLoader:Thread.currentThread().getContextClassLoader()
  • 獲取系統 ClassLoader: ClassLoader.getSystemClassLoader()

不過(guò),若是對 Java 的 ClassLoader 概念不太了解,最好還是盡量避免使用它。

Class.getResource 與 ClassLoader.getResource 的區別

這兩種方式,都接受一個(gè)字符串形式的路徑表達式,即資源名,并返回找到的資源的 URL。兩種方式都可用來(lái)定位資源,在網(wǎng)絡(luò )上流傳的文章中,兩者都是常見(jiàn)的。實(shí)際上,Class 的 getResource 方法也調用了 ClassLoader 的 getResource 方法,但兩者有著(zhù)很大的不同,不了解這兩種方法的區別,就容易造成隱患。隱患經(jīng)常比編寫(xiě)時(shí)就出錯要可怕得多,因為它在一定場(chǎng)合下是正常的,不容易被發(fā)現。

兩者最大的區別,是從哪里開(kāi)始尋找資源。ClassLoader 并不關(guān)心當前類(lèi)的包名路徑,它永遠以 classpath 為基點(diǎn)來(lái)定位資源。而 Class.getResource 則不同,如果資源名是絕對路徑(以"/"開(kāi)頭),它會(huì )將開(kāi)頭的"/"去除,然后調用 ClassLoader 的 getResource 方法來(lái)尋找資源;如果資源名是相對路徑,它會(huì )在當前的包路徑下面尋找資源。

舉例來(lái)說(shuō),假設我們有一個(gè)類(lèi):test.App (包名為 test),并且在 test 包下有一個(gè)與類(lèi)名同名的 js 文件,名為 App.js。如果用 ClassLoader 來(lái)獲取這個(gè) js 文件,應該這樣寫(xiě):

App.class.getClassLoader().getResource("test/App.js");

如果用 Class 的 getResource 方法,則有兩種寫(xiě)法:

  • 使用相對路徑:
App.class.getResource("App.js");
  • 使用絕對路徑:
App.class.getResource("/test/App.js");

從上面的例子,可以看出兩者之間巨大的區別。有些人從網(wǎng)絡(luò )上復制類(lèi)似的代碼,看看不能正確運行,就開(kāi)始嘗試在資源名前加上 "/",或是去掉開(kāi)頭的 "/",試成功了,便算完工,這絕非正道。

Class 與 ClassLoader 的 getResource 方法還有其它一些不同,對 Class 的 getResource 方法來(lái)說(shuō),若傳入的是相對路徑,它還會(huì )嘗試做包名與路徑名的轉換。查看 Class.getResource 方法的源碼,可以看到它首先對資源名調用了 resolveName 方法,然后再調用 ClassLoader 的 getResource 方法來(lái)完成資源的定位。

測試代碼

作為演示,我寫(xiě)了以下代碼來(lái)展示 Class 與 ClassLoader 的 getResource 方法的輸出:

/**
 * Copyright (c) 2014 Chen Zhiqiang <chenzhiqiang@mail.com>. Released under the MIT license.
 */
package test;

import java.net.URL;
import java.util.Enumeration;

/**
 * Tests for the use of {@link Class#getResource(String)} and
 * {@link ClassLoader#getResource(String)}.
 * 
 * @author Chen Zhiqiang <chenzhiqiang@mail.com>
 */
public class ClassResourceTest {
    Class<ClassResourceTest> cls = ClassResourceTest.class;
    ClassLoader ldr = cls.getClassLoader(); // Thread.currentThread().getContextClassLoader()

    public static void println(Object s) {
        System.out.println(s);
    }

    void showResource(String name) {
        println("## Test resource for: “" + name + "” ##");
        println(String.format("ClassLoader#getResource(\"%s\")=%s", name, ldr.getResource(name)));
        println(String.format("Class#getResource(\"%s\")=%s", name, cls.getResource(name)));
    }
    public final void testForResource() throws Exception {
        showResource("");
        showResource("/");
        showResource(cls.getSimpleName() + ".class");
        String n = cls.getName().replace('.', '/') + ".class";
        showResource(n);
        showResource("/" + n);
        showResource("java/lang/Object.class");
        showResource("/java/lang/Object.class");
    }

    public static void main(String[] args) throws Exception {
        println("java.class.path: " + System.getProperty("java.class.path"));
        println("user.dir: " + System.getProperty("user.dir"));
        println("");
        ClassResourceTest t = new ClassResourceTest();
        t.testForResource();
    }
}

編譯上述代碼,看看不同資源路徑的輸出結果。

打包為 Jar 包后的變化

現在,將上述代碼編譯后的結果打包成 Jar 文件,假設是 test.jar ,然后從這個(gè) jar 包中運行上述代碼,再看看輸出結果,比較下與上面的輸出有什么變化:

java -classpath test.jar test.ClassResourceTest

值得注意的幾點(diǎn):

  • Class.getResource("") 還有其它一些輸出,結果是 jar:file:/some_path/test.jar!/some_path,而在打包為 Jar 之前,它們的輸出形式是 file:/some_path...;
  • Class.getResource("/") 為 null,而在打包之前,該輸出是 ClassResourceTest 的類(lèi)路徑;
  • ClassLoader.getResource("") 為 null,而在打包之前,該輸出是 ClassResourceTest 的類(lèi)路徑;
  • 調用 ClassLoader.getResource 方法時(shí),若資源名為絕對路徑,不管是否打包,其輸出結果為 null,至少在我這里是這樣。

錯誤與陷阱

  • 使用 Class.getResource("/") 或 ClassLoader.getResource("") 來(lái)當作類(lèi)路徑的根。

這是一種常見(jiàn)的錯誤,并在網(wǎng)絡(luò )上廣為流傳。它們在打包成 Jar 包后,其結果會(huì )發(fā)生變化。

  • 獲得 getResource 方法的輸出后,簡(jiǎn)單地對結果調用 getFile 或 getPath,并把它當作文件路徑來(lái)處理。

資源有可能以文件和目錄的形式位于類(lèi)路徑之中,但也可能打包進(jìn)了 Jar 包或 Zip 包,你不能假設你的代碼不會(huì )被打包。

  • 將絕對路徑傳給 ClassLoader 的 getResource 方法。

網(wǎng)絡(luò )上有人說(shuō),對于 ClassLoader 的 getResource 方法來(lái)說(shuō),資源名是否以 "/" 開(kāi)頭是一樣的,然而,在我這里,ClassLoader 的 getResource 方法并不接受絕對路徑,其輸出結果為 null。

正確使用 getResource 方法

  • 避免使用 Class.getResource("/") 或 ClassLoader.getResource("")。你應該傳入一個(gè)確切的資源名,然后對輸出結果作計算。比如,如果你確實(shí)想獲取當前類(lèi)是從哪個(gè)類(lèi)路徑起點(diǎn)上執行的,以前面提到的 test.App 來(lái)說(shuō),可以調用 App.class.getResource(App.class.getSimpleName() + ".class")。如果所得結果不是 jar 協(xié)議的URL,說(shuō)明 class 文件沒(méi)有打包,將所得結果去除尾部的 "test/App.class",即可獲得 test.App 的類(lèi)路徑的起點(diǎn);如果結果是 jar 協(xié)議的 URL,去除尾部的 "!/test/App.class",和前面的 "jar:",即是 test.App 所在的 jar 文件的 url。
  • 如果要定位與某個(gè)類(lèi)同一個(gè)包的資源,盡量使用那個(gè)類(lèi)的getResource方法并使用相對路徑。如前文所述,要獲取與 test.App.class 同一個(gè)包下的 App.js 文件,應使用  App.class.getResource("App.js") 。當然,事無(wú)絕對,用 ClassLoader.getResource("test/App.js") 也可以,這取決于你所面對的問(wèn)題是什么。
  • 如果對 ClassLoader 不太了解,那就盡量使用 Class 的 getResource 方法。
  • 如果不理解或無(wú)法確定該傳給 Class.getResource 方法的相對路徑,那就以類(lèi)路徑的頂層包路徑為參考起點(diǎn),總是傳給它以 "/" 開(kāi)頭的路徑吧。
  • 不要假設你的調試環(huán)境就是最后的運行環(huán)境。你的代碼可能不打包,也可能打包,你得考慮這些情況,不要埋坑。

getResources: 枚舉資源

Java 的 CLASSPATH 是一個(gè)路徑列表,因此,有可能在多個(gè)類(lèi)路徑中出現同樣的資源名。如果要列舉它們,可以使用 ClassLoader 的 getResources 方法。

下面的代碼可以枚舉所有的 "META-INF/MANIFEST.MF",你還可以觀(guān)察到在類(lèi)路徑中哪些 jar 文件包含有該資源:

import java.net.URL;
import java.util.Enumeration;
public class Test {
    public static void main(String[] args) throws Exception {
        ClassLoader ldr = Test.class.getClassLoader();
        System.out.println("## Test for getResources(‘META-INF/MANIFEST.MF') ##");
        Enumeration<URL> urls = ldr.getResources("META-INF/MANIFEST.MF");
        while(urls.hasMoreElements())
            System.out.println(urls.nextElement());
    }
}

實(shí)例

下面的代碼演示了如何正確獲取代碼的類(lèi)路徑起點(diǎn):

/**
 * Copyright (c) 2014 Chen Zhiqiang <chenzhiqiang@mail.com>. Released under the MIT license.
 */
package test;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 演示如何獲取當前類(lèi)路徑的起點(diǎn)
 * 
 * @author Chen Zhiqiang <chenzhiqiang@mail.com>
 */
public class AppDirTest {
	Classcls = AppDirTest.class;
	URL codeLocation = getCodeLocation();

	/**
	 * Get the code location.
	 * 
	 * Return the classpath where the code run from. The return url will be:
	 *   file:/path/my-app/calsses/ or file:/path/my-app/my-app.jar
	 *
	 * @return URL
	 */
	public URL getCodeLocation() {
		if (codeLocation != null)
			return codeLocation;
		// Get code location using the CodeSource
		codeLocation = cls.getProtectionDomain().getCodeSource().getLocation();
		if (codeLocation != null)
			return codeLocation;
		// If CodeSource didn't work, use {@link } Class.getResource instead.
		URL r = cls.getResource("");
		synchronized (r) {
			String s = r.toString();
			Pattern jar_re = Pattern.compile("jar:\\s?(.*)!/.*");
			Matcher m = jar_re.matcher(s);
			if (m.find()) { // the code is run from a jar file.
				s = m.group(1);
			} else {
				String p = cls.getPackage().getName().replace('.', '/');
				s = s.substring(0, s.lastIndexOf(p));
			}
			try {
				codeLocation = new URL(s);
			} catch (MalformedURLException e) {
				throw new RuntimeException(e);
			}
		}
		return codeLocation;
	}

	/**
	 * Get the class path root where the program startup, if run in a jar,
	 * return the jar file's parent path.
	 * 
	 * @return
	 */
	public String getAppDir() {
		File f = new File(getCodeLocation().getPath());
		return f.isFile() ? f.getParent() : f.getPath();
	}

	public static void main(String[] args) {
		AppDirTest t = new AppDirTest();
		System.out.println("code location: " + t.getCodeLocation());
		System.out.println("app dir: " + t.getAppDir());
	}

}

以上就是Java 正確地從類(lèi)路徑中獲取資源的詳細內容,更多關(guān)于Java 從類(lèi)路徑中獲取資源的資料請關(guān)注腳本之家其它相關(guān)文章!

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

九九热线精品视频98| 午夜视频在线观看免费完整版| 少妇挑战三个黑人叫声好凄惨| 午夜视频在线观看免费完整版| 国产无套护士在线观看| 天码AV无码一区二区三区四区|