Vorrei conoscere il modo migliore per caricare una risorsa in Java:
this.getClass().getResource() (or getResourceAsStream()),Thread.currentThread().getContextClassLoader().getResource(name),System.class.getResource(name).
Vorrei conoscere il modo migliore per caricare una risorsa in Java:
this.getClass().getResource() (or getResourceAsStream()),Thread.currentThread().getContextClassLoader().getResource(name),System.class.getResource(name).Risposte:
Elabora la soluzione in base a ciò che desideri ...
Ci sono due cose che getResource/ getResourceAsStream()otterrò dalla classe in cui è chiamato ...
Quindi se lo fai
this.getClass().getResource("foo.txt");
tenterà di caricare foo.txt dallo stesso pacchetto della classe "this" e con il class loader della classe "this". Se metti una "/" davanti, stai assolutamente facendo riferimento alla risorsa.
this.getClass().getResource("/x/y/z/foo.txt")
caricherà la risorsa dal class loader di "this" e dal pacchetto xyz (dovrà essere nella stessa directory delle classi in quel pacchetto).
Thread.currentThread().getContextClassLoader().getResource(name)
verrà caricato con il caricatore della classe di contesto ma non risolverà il nome in base a nessun pacchetto (deve essere assolutamente referenziato)
System.class.getResource(name)
Caricherà la risorsa con il caricatore di classi di sistema (dovrebbe anche essere assolutamente referenziato, poiché non sarai in grado di mettere nulla nel pacchetto java.lang (il pacchetto di System).
Dai un'occhiata alla fonte. Indica anche che getResourceAsStream chiama semplicemente "openStream" sull'URL restituito da getResource e lo restituisce.
Thread#setContextClassLoader. Ciò è utile se è necessario modificare il percorso di classe durante l'esecuzione del programma.
Bene, in parte dipende da cosa vuoi che accada se sei effettivamente in una classe derivata.
Ad esempio, supponiamo che SuperClasssia in A.jar e SubClassin B.jar e che tu stia eseguendo codice in un metodo di istanza dichiarato in SuperClassma dove si thisriferisce a un'istanza di SubClass. Se lo usi this.getClass().getResource(), apparirà relativo a SubClass, in B.jar. Sospetto che di solito non sia ciò che è richiesto.
Personalmente probabilmente lo userei Foo.class.getResourceAsStream(name)più spesso: se conosci già il nome della risorsa che stai cercando e sei sicuro di dove è relativo Foo, questo è il modo più robusto per farlo IMO.
Naturalmente ci sono momenti in cui non è quello che vuoi anche tu: giudica ogni caso in base ai suoi meriti. È solo che "So che questa risorsa è in bundle con questa classe" è la più comune in cui mi sono imbattuto.
this.getClass(). Crea un'istanza della sottoclasse e chiama il metodo ... stamperà il nome della sottoclasse, non la superclasse.
Cerco tre posti come mostrato di seguito. Commenti benvenuti.
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);
}
So che è davvero tardi per un'altra risposta, ma volevo solo condividere ciò che mi ha aiutato alla fine. Caricherà anche risorse / file dal percorso assoluto del file system (non solo quello del 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;
}
}
Ho provato molti modi e funzioni che ho suggerito sopra, ma non hanno funzionato nel mio progetto. Comunque ho trovato la soluzione ed eccola qui:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
this.getClass().getResourceAsStream()in questo caso. Se dai un'occhiata alla fonte del getResourceAsStreammetodo, noterai che fa la stessa cosa di te ma in un modo più intelligente (fallback se non ClassLoaderpuò essere trovato nella classe). Esso indica inoltre che è possibile incontrare un potenziale nullsu getClassLoadernel codice ...
this.getClass().getResourceAsStream()non funziona per me, quindi lo uso funziona. Penso che ci siano alcune persone che possono affrontare problemi come il mio.