215

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()です。しかし、明らかにそうではありません。誰かが私にこの問題についての照明を提供してくれませんか?

4

9 に答える 9

280

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");
于 2011-07-07T10:03:59.750 に答える
26

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

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

System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );
于 2011-07-07T10:02:16.027 に答える
19

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

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

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

于 2011-07-07T10:03:41.920 に答える
12

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

于 2013-11-19T11:04:49.860 に答える
7

キャッシングが行われているかどうかという質問に答えるため。

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

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

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

于 2012-05-15T08:49:01.323 に答える
2

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

于 2014-08-14T09:12:47.433 に答える
2

Java 9以降ClassLoader#getResource、モジュールパスで実行する場合に落とし穴があります。ClassLoader#getResourceこのため、新しいコードで使用することはありません。

コードが名前付きモジュールにあり、を使用している場合、リソースが同じモジュールにある場合でもClassLoader#getResource、コードはリソースの取得に失敗する可能性があります。これは非常に驚くべき動作です。

私はこれを自分で経験し、とのこの違いに非常に驚いていましClass#getResourceClassLoader#getResource。ただし、javadocによると完全に指定された動作です。

さらに、リソースの名前が「.class」で終わる特殊なケースを除いて、このメソッドは、パッケージが無条件に開かれた場合にのみ、名前付きモジュールのパッケージ内のリソースを検索します(このメソッドの呼び出し元が同じである場合でも)リソースとしてのモジュール)。

Javadoc(強調鉱山)

于 2021-04-04T01:32:36.273 に答える
0

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

次の作品:

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

System.out.println(fileName);

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

最も重要な部分はgetPath()、文字列形式の正しいパス名が必要な場合に呼び出すことでした。fileNameを完全に台無しにする余分なフォーマットテキストが追加されるため、使用しないでください(試して印刷を確認できます)toString()

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

于 2014-03-11T13:34:15.900 に答える
0

もう1つのより効率的な方法は、@Valueを使用することです。

@Value("classpath:sss.json")
private Resource resource;

その後、この方法でファイルを取得できます

File file = resource.getFile();

于 2021-01-06T08:29:30.217 に答える