Was ist der Unterschied zwischen Class.getResource() und ClassLoader.getResource()?

Lesezeit: 7 Minuten

Was ist der Unterschied zwischen ClassgetResource und ClassLoadergetResource
Oligofren

Ich frage mich, was der Unterschied zwischen ist Class.getResource() und ClassLoader.getResource()?

Bearbeiten: Ich möchte besonders wissen, ob Caching auf Datei-/Verzeichnisebene beteiligt ist. Wie in “Werden Verzeichnislisten in der Klassenversion zwischengespeichert?”

AFAIK sollten die folgenden im Wesentlichen dasselbe tun, sind es aber nicht:

getClass().getResource() 
getClass().getClassLoader().getResource()

Ich habe dies entdeckt, als ich mit einem Code zur Berichterstellung herumgespielt habe, der eine neue Datei in erstellt WEB-INF/classes/ aus einer vorhandenen Datei in diesem Verzeichnis. Bei Verwendung der Methode von Class konnte ich Dateien finden, die bei der Bereitstellung vorhanden waren getClass().getResource(), aber beim Versuch, die neu erstellte Datei abzurufen, habe ich ein Nullobjekt erhalten. Das Durchsuchen des Verzeichnisses zeigt deutlich, dass die neue Datei dort ist. Den Dateinamen wurde ein Schrägstrich wie in “/myFile.txt” vorangestellt.

Die ClassLoader Version von getResource() hingegen fand die generierte Datei. Aus dieser Erfahrung scheint es, dass eine Art Caching der Verzeichnisliste stattfindet. Liege ich richtig, und wenn ja, wo ist das dokumentiert?

Von dem API-Dokumente an Class.getResource()

Findet eine Ressource mit einem bestimmten Namen. Die Regeln zum Suchen von Ressourcen, die einer gegebenen Klasse zugeordnet sind, werden durch den definierenden Klassenlader der Klasse implementiert. Diese Methode delegiert an den Klassenlader dieses Objekts. Wenn dieses Objekt vom Bootstrap-Klassenlader geladen wurde, delegiert die Methode an ClassLoader.getSystemResource(java.lang.String).

Für mich lautet dies “Class.getResource ruft wirklich getResource() seines eigenen Classloaders auf”. Was dasselbe wäre wie tun getClass().getClassLoader().getResource(). Aber das ist es offensichtlich nicht. Könnte mir bitte jemand etwas Licht in diese Sache bringen?

1646494032 749 Was ist der Unterschied zwischen ClassgetResource und ClassLoadergetResource
Jon Skeet

Class.getResource kann einen “relativen” Ressourcennamen annehmen, der relativ zum Paket der Klasse behandelt wird. Alternativ können Sie einen “absoluten” Ressourcennamen angeben, indem Sie einen führenden Schrägstrich verwenden. Classloader-Ressourcenpfade gelten immer als absolut.

Also die folgenden sind im Grunde gleichwertig:

foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");

Und so sind diese (aber sie unterscheiden sich von den oben genannten):

foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");

  • Schöne Antwort mit klaren Beispielen. Obwohl der Beitrag eigentlich dazu gedacht war, Antworten auf zwei Fragen zu bekommen, sehe ich jetzt, dass die zweite Frage irgendwie versteckt ist. Ich bin mir ziemlich unsicher, wie / ob ich den Beitrag aktualisieren soll, um dies widerzuspiegeln, aber was ich als zweites wissen möchte, ist Folgendes (nächster Kommentar):

    – Oligofren

    7. Juli 2011 um 16:04 Uhr

  • Gibt es eine Art Caching in der Class.getResource()-Version? Was mich dazu veranlasst hat, dies zu glauben, ist die Generierung einiger Jasper-Berichte: Wir verwenden getClass().getResource(“/aDocument.jrxml”), um die Jasper-XML-Datei abzurufen. Eine binäre Jaspis-Datei wird dann in der erstellt gleich Verzeichnis. getClass().getResource(“/aDocument.jasper”) kann es nicht finden, obwohl es eindeutig Dokumente auf derselben Ebene (der Eingabedatei) finden kann. Hier hat sich ClassLoader.getResource() als hilfreich erwiesen, da es anscheinend kein Caching der Verzeichnisliste verwendet. Aber ich kann keine Dokumentation dazu finden.

    – Oligofren

    7. Juli 2011 um 16:08 Uhr

  • @oligofren: Hmm … würde ich nicht erwarten Class.getResource(), um dort Caching durchzuführen …

    – Jon Skeet

    7. Juli 2011 um 16:18 Uhr

  • @ JonSkeet warum this.getClass().getClassLoader().getResource("/"); Null zurückgeben? Es sollte nicht dasselbe sein wie this.getClass().getClassLoader().getResource(".");

    – Asif Mushtaq

    16. Februar 2018 um 22:20 Uhr

  • @UnKnown: Ich denke, Sie sollten wahrscheinlich eine neue Frage dazu stellen.

    – Jon Skeet

    17. Februar 2018 um 8:06 Uhr

Was ist der Unterschied zwischen ClassgetResource und ClassLoadergetResource
Aaron Digulla

Der erste Aufruf sucht relativ zum .class Datei, während letztere relativ zum Klassenpfadstamm sucht.

Um solche Probleme zu debuggen, drucke ich die URL:

System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );

  • Ich denke, “classloader root” wäre genauer als “classpath root” – nur um wählerisch zu sein.

    – Jon Skeet

    7. Juli 2011 um 10:14 Uhr

  • Beide können “absolute Pfade” suchen, wenn dem Dateinamen ein “/” vorangestellt ist.

    – Oligofren

    7. Juli 2011 um 15:59 Uhr

  • Interessant … Ich stoße auf einen Fall, in dem getClass().getResource(“/someAbsPath”) eine URL im Typ /path/to/mylib.jar!/someAbsPath und getClass().getClassLoafer().getResource(” zurückgibt /someAbsPath”) gibt null zurück … Also scheint “Root of Classloader” kein sehr gut definierter Begriff zu sein …

    – Pierre Heinrich

    16. April 2013 um 14:35 Uhr

  • siehe stackoverflow.com/questions/13269556/…

    – Pierre Heinrich

    16. April 2013 um 14:36 ​​Uhr

  • @PierreHenry: getClassLoader().getResource("/...") kehrt immer zurück null – Der Classloader entfernt die führende nicht / aus dem Pfad, sodass die Suche immer fehlschlägt. Nur getClass().getResource() behandelt einen Start / als absoluter Pfad relativ zum Klassenpfad.

    – Aaron Digulla

    16. April 2013 um 14:43 Uhr


1646494034 78 Was ist der Unterschied zwischen ClassgetResource und ClassLoadergetResource
Bernd Elkemann

Musste in den technischen Daten nachschauen:

Die getResource() – Dokumentation der Klasse gibt den Unterschied an:

Diese Methode delegiert den Aufruf an ihren Klassenlader, nachdem sie diese Änderungen am Ressourcennamen vorgenommen hat: Wenn der Ressourcenname mit „https://stackoverflow.com/“ beginnt, bleibt er unverändert; andernfalls wird der Paketname dem Ressourcennamen vorangestellt, nachdem “.” zu “https://stackoverflow.com/”. Wenn dieses Objekt vom Bootstrap Loader geladen wurde, wird der Aufruf an ClassLoader.getSystemResource delegiert.

  • Haben Sie Informationen darüber, ob es auch die Verzeichnisliste zwischenspeichert? Dies war der Hauptunterschied zwischen den beiden Methoden, wenn zuerst eine Eingabedatei gesucht und dann eine Datei mit dieser im selben Verzeichnis erstellt wurde. Die Class-Version hat es nicht gefunden, die ClassLoader-Version (beide mit “/file.txt”).

    – Oligofren

    7. Juli 2011 um 16:22 Uhr

1646494034 802 Was ist der Unterschied zwischen ClassgetResource und ClassLoadergetResource
Tim Büthe

Alle diese Antworten hier sowie die Antworten in dieser Frage deuten darauf hin, dass das Laden absoluter URLs wie “/foo/bar.properties” von gleich behandelt wird class.getResourceAsStream(String) und class.getClassLoader().getResourceAsStream(String). Dies ist NICHT der Fall, zumindest nicht in meiner Tomcat-Konfiguration/Version (derzeit 7.0.40).

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

Tut mir leid, ich habe absolut keine befriedigende Erklärung, aber ich vermute, dass Kater mit den Classloadern schmutzige Tricks und seine schwarze Magie anstellt und den Unterschied verursacht. Ich habe immer verwendet class.getResourceAsStream(String) in der Vergangenheit und hatte keine Probleme.

PS: Das habe ich auch hier gepostet

Um die Frage zu beantworten, ob Caching stattfindet.

Ich habe diesen Punkt weiter untersucht, indem ich eine eigenständige Java-Anwendung ausgeführt habe, die mit der getResourceAsStream-ClassLoader-Methode kontinuierlich eine Datei von der Festplatte geladen hat. Ich konnte die Datei bearbeiten, und die Änderungen wurden sofort wiedergegeben, dh die Datei wurde ohne Zwischenspeicherung von der Festplatte neu geladen.

Aber:
Ich arbeite an einem Projekt mit mehreren Maven-Modulen und Webprojekten, die voneinander abhängig sind. Ich verwende IntelliJ als meine IDE, um die Webprojekte zu kompilieren und auszuführen.

Mir ist aufgefallen, dass das oben Gesagte nicht mehr zuzutreffen schien, da die Datei, die ich gerade geladen habe, jetzt in ein JAR gebacken und für das abhängige Webprojekt bereitgestellt wird. Ich habe dies erst bemerkt, nachdem ich vergeblich versucht hatte, die Datei in meinem Zielordner zu ändern. Dies ließ den Anschein erwecken, als würde Caching stattfinden.

  • Ich habe auch Maven und IntelliJ verwendet, daher ist dies die Antwort in einer Umgebung, die meiner am ehesten entspricht und eine vernünftige Erklärung für Frage Nr. 2 enthält.

    – Oligofren

    10. Januar 2014 um 9:55 Uhr

Was ist der Unterschied zwischen ClassgetResource und ClassLoadergetResource
Hackjutsu

Class.getResources würde die Ressource durch den Klassenlader abrufen, der das Objekt lädt. Während ClassLoader.getResource würde die Ressource mit dem angegebenen Classloader abrufen.

  • Ich habe auch Maven und IntelliJ verwendet, daher ist dies die Antwort in einer Umgebung, die meiner am ehesten entspricht und eine vernünftige Erklärung für Frage Nr. 2 enthält.

    – Oligofren

    10. Januar 2014 um 9:55 Uhr

1646494038 555 Was ist der Unterschied zwischen ClassgetResource und ClassLoadergetResource
A248

Seit Java 9 gibt es eine Falle mit ClassLoader#getResource beim Ausführen auf dem Modulpfad. Aus diesem Grund würde ich nie verwenden ClassLoader#getResource im neuen Code.

Wenn sich Ihr Code in einem benannten Modul befindet und Sie verwenden ClassLoader#getResourcekann es sein, dass Ihr Code eine Ressource nicht abrufen kann auch wenn sich die Ressource im selben Modul befindet. Dies ist ein sehr überraschendes Verhalten.

Ich habe das selbst erlebt und war sehr überrascht über diesen Unterschied zwischen Class#getResource und ClassLoader#getResource. Es handelt sich jedoch laut Javadoc um ein vollständig spezifiziertes Verhalten:

Abgesehen von dem Sonderfall, in dem die Ressource einen Namen hat, der mit „.class“ endet, findet diese Methode außerdem nur Ressourcen in Paketen mit benannten Modulen, wenn das Paket bedingungslos geöffnet wird (auch wenn sich der Aufrufer dieser Methode im selben Modul wie die Ressource befindet).

Javadoc (Hervorhebung von mir)

  • verwandt: Was ist ein offenes Modul in Java 9 und wie verwende ich es?

    – jaco0646

    8. April 2021 um 14:34 Uhr

947430cookie-checkWas ist der Unterschied zwischen Class.getResource() und ClassLoader.getResource()?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy