Saya ingin tahu cara terbaik memuat sumber daya di Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.
Saya ingin tahu cara terbaik memuat sumber daya di Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.Jawaban:
Cari solusinya sesuai dengan yang Anda inginkan ...
Ada dua hal yang akan getResource
/ getResourceAsStream()
dapatkan dari kelas tempat dipanggilnya ...
Jadi jika Anda melakukannya
this.getClass().getResource("foo.txt");
ini akan mencoba memuat foo.txt dari paket yang sama dengan kelas "this" dan dengan pemuat kelas dari kelas "this". Jika Anda meletakkan "/" di depan maka Anda benar-benar mereferensikan sumber daya.
this.getClass().getResource("/x/y/z/foo.txt")
akan memuat sumber daya dari pemuat kelas "this" dan dari paket xyz (ini harus berada di direktori yang sama dengan kelas dalam paket itu).
Thread.currentThread().getContextClassLoader().getResource(name)
akan memuat dengan pemuat kelas konteks tetapi tidak akan menyelesaikan nama sesuai dengan paket apa pun (itu harus benar-benar direferensikan)
System.class.getResource(name)
Akan memuat sumber daya dengan pemuat kelas sistem (itu harus benar-benar direferensikan juga, karena Anda tidak akan dapat memasukkan apa pun ke dalam paket java.lang (paket Sistem).
Lihat saja sumbernya. Juga menunjukkan bahwa getResourceAsStream hanya memanggil "openStream" pada URL yang ditampilkan dari getResource dan menampilkannya.
Thread#setContextClassLoader
. Ini berguna jika Anda perlu mengubah jalur kelas saat program sedang dijalankan.
Yah, itu sebagian tergantung pada apa yang Anda inginkan terjadi jika Anda benar - benar berada di kelas turunan.
Misalnya, anggap SuperClass
dalam A.jar dan SubClass
dalam B.jar, dan Anda menjalankan kode dalam metode instance yang dideklarasikan SuperClass
tetapi di mana this
merujuk ke instance SubClass
. Jika Anda menggunakannya this.getClass().getResource()
akan terlihat relatif SubClass
, di B.jar. Saya rasa biasanya bukan itu yang diminta.
Secara pribadi saya mungkin Foo.class.getResourceAsStream(name)
paling sering menggunakan - jika Anda sudah tahu nama sumber daya yang Anda cari, dan Anda yakin di mana itu relatif Foo
, itulah cara paling kuat untuk melakukannya IMO.
Tentu saja ada kalanya Anda juga tidak menginginkannya: menilai setiap kasus berdasarkan manfaatnya. Hanya "Saya tahu sumber daya ini digabungkan dengan kelas ini" adalah yang paling umum yang pernah saya temui.
this.getClass()
. Buat sebuah instance dari subclass dan panggil metode ... itu akan mencetak nama subclass tersebut, bukan superclassnya.
Saya mencari tiga tempat seperti yang ditunjukkan di bawah ini. Komentar diterima.
public URL getResource(String resource){
URL url ;
//Try with the Thread Context Loader.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader != null){
url = classLoader.getResource(resource);
if(url != null){
return url;
}
}
//Let's now try with the classloader that loaded this class.
classLoader = Loader.class.getClassLoader();
if(classLoader != null){
url = classLoader.getResource(resource);
if(url != null){
return url;
}
}
//Last ditch attempt. Get the resource from the classpath.
return ClassLoader.getSystemResource(resource);
}
Saya tahu ini sangat terlambat untuk jawaban lain tetapi saya hanya ingin berbagi apa yang membantu saya pada akhirnya. Ini juga akan memuat resource / file dari jalur absolut sistem file (tidak hanya classpath).
public class ResourceLoader {
public static URL getResource(String resource) {
final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
classLoaders.add(Thread.currentThread().getContextClassLoader());
classLoaders.add(ResourceLoader.class.getClassLoader());
for (ClassLoader classLoader : classLoaders) {
final URL url = getResourceWith(classLoader, resource);
if (url != null) {
return url;
}
}
final URL systemResource = ClassLoader.getSystemResource(resource);
if (systemResource != null) {
return systemResource;
} else {
try {
return new File(resource).toURI().toURL();
} catch (MalformedURLException e) {
return null;
}
}
}
private static URL getResourceWith(ClassLoader classLoader, String resource) {
if (classLoader != null) {
return classLoader.getResource(resource);
}
return null;
}
}
Saya mencoba banyak cara dan fungsi yang disarankan di atas, tetapi tidak berhasil dalam proyek saya. Pokoknya saya sudah menemukan solusinya dan ini dia:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
this.getClass().getResourceAsStream()
dalam kasus ini. Jika Anda melihat sumber getResourceAsStream
metode, Anda akan melihat bahwa ia melakukan hal yang sama dari Anda tetapi dengan cara yang lebih cerdas (fallback jika tidak ada yang ClassLoader
dapat ditemukan di kelas). Ini juga menunjukkan bahwa Anda dapat menemukan potensi null
di getClassLoader
dalam kode Anda…
this.getClass().getResourceAsStream()
tidak berfungsi untuk saya, jadi saya menggunakan yang berfungsi. Saya pikir ada beberapa orang yang bisa menghadapi masalah seperti saya.