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


194

私は違いが間にあるのだろうかClass.getResource()ClassLoader.getResource()

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

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

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

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

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

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

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

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

回答:


6

キャッシングが行われているかどうかの質問に答えます。

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

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

上記が当てはまらなくなったようです。理由は、ロードされていたファイルがjarにベイクされ、依存するWebプロジェクトにデプロイされているためです。私がこれに気付いたのは、ターゲットフォルダー内のファイルを変更しようとしたが、役に立たなかったためです。これにより、キャッシュが行われているように見えました。


私もMavenとIntelliJを使用したので、これは私の環境に最も近い環境での回答であり、質問#2について合理的な説明があります。
オリゴフレン2014年

249

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");

明確な例でいい答え。投稿は実際には2つの質問への回答を得ることを目的としていましたが、2番目の質問はある程度隠されていることがわかりました。これを反映するために投稿をどのように/どのように更新するべきかはまったくわかりませんが、2番目に知りたいのはこれです(次のコメント):
オリゴフレン

2
Class.getResource()バージョンで何らかのキャッシュが行われていますか?これがいくつかのジャスパーレポートの生成であると私に思わせたのは、ジャスパーxmlファイルをフェッチするためにgetClass()。getResource( "/ aDocument.jrxml")を使用することです。次に、バイナリジャスパーファイルが同じディレクトリに作成されます。getClass()。getResource( "/ aDocument.jasper")はそれを見つけることができませんが、同じレベル(入力ファイル)のドキュメントを明確に見つけることができます。これは、ClassLoader.getResource()が役立つことを証明した場所です。ディレクトリリストのキャッシュを使用していないようです。しかし、これに関するドキュメントは見つかりません。
オリゴフレン2011

2
@oligofren:うーん...私はないだろう期待 Class.getResourceは()が任意のキャッシュを行うために...
ジョンスキート

1
@JonSkeet this.getClass().getClassLoader().getResource("/");nullを返す理由 それは同じであってはなりませんthis.getClass().getClassLoader().getResource(".");
Asif Mushtaq 2018

@UnKnown:あなたはおそらくそれについて新しい質問をするべきだと思います。
Jon Skeet、2018

22

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

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

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

3
「クラスローダールート」は「クラスパスルート」よりも正確だと思います。
Jon Skeet、2011

4
ファイル名は、「/」によって付加されている場合は両方とも「絶対パス」を検索することができます
oligofren

2
興味深い... getClass()。getResource( "/ someAbsPath")がタイプ/path/to/mylib.jar!/someAbsPathとgetClass()。getClassLoafer()。getResource( ")のURLを返す場合に遭遇しています。 / someAbsPath ")はnullを返します...したがって、「クラスローダーのルート」は明確に定義された概念ではないようです...
ピエールヘンリー


8
@PierreHenry:getClassLoader().getResource("/...")常に戻り値null-クラスローダーは/パスの先頭を削除しないため、検索は常に失敗します。クラスパスを基準とした絶対パスとしてのみgetClass().getResource()開始/を処理します。
アーロンディグラ2013

17

スペックで調べなければなりませんでした:

クラスのgetResource()-ドキュメントは違いを述べています:

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


2
ディレクトリリストもキャッシュするかどうかについての情報はありますか?これは、最初に入力ファイルを検索し、それを使用して同じディレクトリにファイルを作成するときの2つの方法の主な違いでした。クラスのバージョンでは見つかりませんでした。クラスローダーのバージョンでは見つかりました(両方とも "/file.txt"を使用しています)。
オリゴフレン

11

ここにあるこれらすべての回答、およびこの質問の回答は、「/ 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:これもここに投稿しまし


この動作は、私は私の中でそのことについての段落を追加し、バージョン8で修正されたのTomcatのバグのように見えるこの質問についての答え
LordOfThePigs

2

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


0

私のパッケージの中にあるinput1.txtから、それを読み込もうとしたクラスと一緒に読み込もうとしました。

次の作品:

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

System.out.println(fileName);

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

最も重要な部分はgetPath()、String形式の正しいパス名が必要な場合に呼び出すことでした。使用しtoString()ないでください。これにより、fileNameが完全に失われる追加の書式設定テキストが追加されます(試してみると、印刷結果を確認できます)。

これをデバッグするのに2時間を費やした... :(



リソースはファイルではありません。それらはJARまたはWARファイルからアンパックされない場合があり、そうでない場合はそれらにアクセスするために使用できないFileReaderか、またはFileInputStream使用できません。正解ではありません。
ローン侯爵
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.