Ich möchte wissen, wie eine Ressource am besten in Java geladen werden kann:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.
Ich möchte wissen, wie eine Ressource am besten in Java geladen werden kann:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.Antworten:
Erarbeiten Sie die Lösung nach Ihren Wünschen ...
Es gibt zwei Dinge , die getResource
/ getResourceAsStream()
aus der Klasse erhalten wird er am genannt wird ...
Also wenn du es tust
this.getClass().getResource("foo.txt");
Es wird versucht, foo.txt aus demselben Paket wie die "this" -Klasse und mit dem Klassenladeprogramm der "this" -Klasse zu laden. Wenn Sie ein "/" voranstellen, verweisen Sie absolut auf die Ressource.
this.getClass().getResource("/x/y/z/foo.txt")
lädt die Ressource aus dem Klassenlader von "this" und aus dem xyz-Paket (sie muss sich im selben Verzeichnis wie die Klassen in diesem Paket befinden).
Thread.currentThread().getContextClassLoader().getResource(name)
wird mit dem Kontextklassenlader geladen, löst den Namen jedoch nicht gemäß einem Paket auf (es muss unbedingt referenziert werden)
System.class.getResource(name)
Lädt die Ressource mit dem Systemklassenlader (es müsste auch unbedingt referenziert werden, da Sie nichts in das Paket java.lang (das Paket von System) einfügen können.
Schauen Sie sich einfach die Quelle an. Gibt außerdem an, dass getResourceAsStream nur "openStream" für die von getResource zurückgegebene URL aufruft und diese zurückgibt.
Thread#setContextClassLoader
. Dies ist nützlich, wenn Sie den Klassenpfad ändern müssen, während das Programm ausgeführt wird.
Nun, es hängt teilweise davon ab, was passieren soll, wenn Sie tatsächlich in einer abgeleiteten Klasse sind.
Angenommen, es SuperClass
befindet sich in A.jar und SubClass
in B.jar, und Sie führen Code in einer Instanzmethode aus, die in deklariert ist SuperClass
, wobei this
sich jedoch auf eine Instanz von bezieht SubClass
. Wenn Sie es verwenden this.getClass().getResource()
, wird es relativ zu SubClass
, in B.jar aussehen. Ich vermute, dass dies normalerweise nicht erforderlich ist.
Persönlich würde ich wahrscheinlich Foo.class.getResourceAsStream(name)
am häufigsten verwenden - wenn Sie den Namen der Ressource, nach der Sie suchen, bereits kennen und sicher sind, wo er sich relativ Foo
befindet, ist dies die robusteste Methode, dies IMO zu tun.
Natürlich gibt es Zeiten, in denen Sie das auch nicht wollen: Beurteilen Sie jeden Fall nach seinen Vorzügen. Es ist nur die "Ich weiß, dass diese Ressource mit dieser Klasse gebündelt ist" die häufigste, auf die ich gestoßen bin.
this.getClass()
. Erstellen Sie eine Instanz der Unterklasse und rufen Sie die Methode auf. Sie gibt den Namen der Unterklasse aus, nicht die Oberklasse.
Ich suche drei Orte wie unten gezeigt. Kommentare willkommen.
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);
}
Ich weiß, dass es für eine weitere Antwort sehr spät ist, aber ich wollte nur mitteilen, was mir am Ende geholfen hat. Es werden auch Ressourcen / Dateien aus dem absoluten Pfad des Dateisystems geladen (nicht nur aus dem Klassenpfad).
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;
}
}
Ich habe viele Möglichkeiten und Funktionen ausprobiert, die oben vorgeschlagen wurden, aber sie haben in meinem Projekt nicht funktioniert. Jedenfalls habe ich eine Lösung gefunden und hier ist sie:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
this.getClass().getResourceAsStream()
in diesem Fall besser verwenden . Wenn Sie sich die Quelle der getResourceAsStream
Methode ansehen , werden Sie feststellen, dass sie dasselbe tut wie Sie, jedoch auf intelligentere Weise (Fallback, wenn ClassLoader
in der Klasse keine gefunden werden kann). Es zeigt auch , dass Sie ein Potential begegnen können null
auf getClassLoader
im Code ...
this.getClass().getResourceAsStream()
nicht für mich, also benutze ich das. Ich denke, es gibt einige Leute, die mit Problemen wie meinen konfrontiert werden können.