web-dev-qa-db-ja.com

Class.getResource()とClassLoader.getResource()の違いは何ですか?

Class.getResource()ClassLoader.getResource()の違いは何ですか?

編集:ファイル/ディレクトリレベルでキャッシングが関係しているかどうかを特に知りたいです。 「ディレクトリバージョンはクラスバージョンでキャッシュされますか?」

知っている限り、以下は本質的に同じことをするはずですが、そうではありません:

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

そのディレクトリ内の既存のファイルからWEB-INF/classes/に新しいファイルを作成するレポート生成コードをいじると、これを発見しました。 Classのメソッドを使用すると、getClass().getResource()を使用してデプロイメント時に存在するファイルを見つけることができましたが、新しく作成されたファイルをフェッチしようとすると、nullオブジェクトを受け取りました。ディレクトリを参照すると、新しいファイルが存在することが明確に示されます。ファイル名の先頭には、「/ myFile.txt」のようにスラッシュが追加されました。

一方、getResource()ClassLoaderバージョンは、生成されたファイルを見つけました。この経験から、進行中のディレクトリ一覧の何らかのキャッシュが存在するようです。私は正しいですか、もしそうなら、これはどこに文書化されていますか?

Class.getResource()APIドキュメント から

指定された名前のリソースを検索します。特定のクラスに関連付けられたリソースを検索するためのルールは、クラスの定義クラスローダーによって実装されます。このメソッドは、このオブジェクトのクラスローダーに委任します。このオブジェクトがbootstrapクラスローダーによってロードされた場合、メソッドはClassLoader.getSystemResource(Java.lang.String)に委任します。

私には、「Class.getResourceは実際に独自のクラスローダーのgetResource()を呼び出しています」と表示されます。これはgetClass().getClassLoader().getResource()を実行するのと同じです。しかし、明らかにそうではありません。誰かがこの問題に何らかの照明を提供してもらえますか?

181
oligofren

進行中のキャッシュがあるかどうかの質問に答えるため。

GetResourceAsStream ClassLoaderメソッドを使用してディスクからファイルを継続的にロードするスタンドアロンJavaアプリケーションを実行することにより、この点をさらに調査しました。ファイルを編集することができ、変更はすぐに反映されました。つまり、ファイルはキャッシュせずにディスクからリロードされました。

ただし:私は、互いに依存関係のある複数のMavenモジュールとWebプロジェクトを持つプロジェクトに取り組んでいます。 IntelliJをIDEとして使用して、Webプロジェクトをコンパイルおよび実行しています。

ロードされていたファイルがjarにベイクされ、依存するWebプロジェクトにデプロイされているため、上記はもはや当てはまらないように思えました。これに気づいたのは、ターゲットフォルダー内のファイルを無効にしようとした後です。これにより、キャッシュが行われているように見えました。

5
mchlstckl

Class.getResourceは、「相対」リソース名を取ることができます。これは、クラスのパッケージに関連して処理されます。または、先頭のスラッシュを使用して「絶対」リソース名を指定できます。クラスローダーのリソースパスは常に絶対パスと見なされます。

したがって、以下は基本的に同等です。

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

これらも同様です(ただし、上記とは異なります)。

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

最初の呼び出しは.classファイルに関連して検索し、後者はクラスパスルートに関連して検索します。

そのような問題をデバッグするには、URLを印刷します。

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

仕様で調べなければなりませんでした:

クラスのgetResource()-ドキュメントには違いが記載されています:

このメソッドは、リソース名にこれらの変更を加えた後、クラスローダーに呼び出しを委任します。リソース名が「/」で始まる場合、変更されません。そうでない場合、パッケージ名は「。」の変換後にリソース名の前に追加されます。 「/」に。このオブジェクトがbootstrapローダーによってロードされた場合、呼び出しはClassLoader.getSystemResourceに委任されます。

16
Bernd Elkemann

ここでのこれらすべての答えと この質問 の答えは、「/ foo/bar.properties」のような絶対URLのロードがclass.getResourceAsStream(String)class.getClassLoader().getResourceAsStream(String)によって同じように扱われることを示唆しています。少なくとも私のTomcat構成/バージョン(現在7.0.40)ではそうではありません。

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

申し訳ありませんが、満足のいく説明はまったくありませんが、Tomcatはクラスローダーで汚いトリックと彼の黒魔術を行い、違いを引き起こしていると思います。過去にclass.getResourceAsStream(String)を使用していましたが、問題はありませんでした。

PS:私もこれを投稿しました here

10
Tim Büthe

Class.getResourcesは、オブジェクトをロードするクラスローダーによってリソースを取得します。 ClassLoader.getResourceは、指定されたクラスローダーを使用してリソースを取得します。

2
lwpro2

パッケージの1つ内にあるinput1.txtを、読み取ろうとしているクラスと一緒に読み取ろうとしました。

次の作品:

String fileName = FileTransferClient.class.getResource("input1.txt").getPath();

System.out.println(fileName);

BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));

最も重要な部分は、ストリング形式の正しいパス名が必要な場合にgetPath()を呼び出すことでした。 toString()を使用しないでください fileNameを完全に混乱させる余分な書式設定テキストを追加するため(これを試して印刷を確認できます)。

これをデバッグするのに2時間かかりました... :(

0
Kevin Lee