В чем разница между Class.getResource () и ClassLoader.getResource ()? - PullRequest
183 голосов
/ 07 июля 2011

Интересно, в чем разница между Class.getResource() и ClassLoader.getResource()?

edit: я особенно хочу знать, задействовано ли какое-либо кэширование на уровне файлов / каталогов. Как в «кэшируются ли списки каталогов в версии класса?»

AFAIK следующие должны по существу делать то же самое, но это не так:

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

Я обнаружил это, когда возился с кодом генерации отчетов, который создает новый файл в WEB-INF/classes/ из существующего файла в этом каталоге. При использовании метода из класса я мог найти файлы, которые были там при развертывании, используя getClass().getResource(), но при попытке извлечь только что созданный файл я получил нулевой объект. Просмотр каталога ясно показывает, что новый файл есть. К именам файлов добавляется косая черта, как в "/myFile.txt".

С другой стороны, ClassLoader версия getResource() нашла сгенерированный файл. Из этого опыта кажется, что происходит какое-то кэширование списка каталогов. Я прав, и если да, то где это задокументировано?

Из API документов на Class.getResource()

Находит ресурс с заданным именем. Правила для поиск ресурсов, связанных с данный класс реализуется определение класса загрузчик класса. Этот метод делегирует этому объекту класс загрузчик. Если этот объект был загружается загрузчиком класса начальной загрузки, метод делегирует ClassLoader.getSystemResource (java.lang.String).

Для меня это выглядит так: «Class.getResource действительно вызывает свой собственный загрузчик классов getResource ()». Что было бы так же, как делать getClass().getClassLoader().getResource(). Но это явно не так. Может ли кто-нибудь дать мне некоторое представление об этом?

Ответы [ 7 ]

227 голосов
/ 07 июля 2011

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");
21 голосов
/ 07 июля 2011

Первый поиск выполняется относительно файла .class, а последний - относительно корня пути к классам.

Для устранения подобных проблем я печатаю URL:

System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );
16 голосов
/ 07 июля 2011

Пришлось искать его в спецификации:

Класс getResource () - документация утверждает разницу:

Этот метод делегирует вызов егозагрузчик классов, после внесения этих изменений в имя ресурса: если имя ресурса начинается с "/", оно не изменяется;в противном случае имя пакета добавляется к имени ресурса после преобразования "."в "/".Если этот объект был загружен загрузчиком начальной загрузки, вызов делегируется ClassLoader.getSystemResource.

10 голосов
/ 19 ноября 2013

Все эти ответы здесь, а также ответы в на этот вопрос предполагают, что загрузка абсолютных URL, таких как "/foo/bar.properties", обрабатывается одинаково при 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!

Извините, у меня нет абсолютно никакого удовлетворительного объяснения, но я думаю, что кот делает грязные трюки и свою черную магию с загрузчиками классов и вызывает разницу. Я всегда использовал class.getResourceAsStream(String) в прошлом и у меня не было проблем.

PS: Я также разместил это более здесь

5 голосов
/ 15 мая 2012

Чтобы ответить на вопрос, происходит ли кэширование.

Я исследовал этот вопрос дополнительно, запустив отдельное приложение Java, которое непрерывно загружало файл с диска с помощью метода getResourceAsStream ClassLoader. Мне удалось отредактировать файл, и изменения сразу же были отражены, то есть файл был перезагружен с диска без кэширования.

Однако: Я работаю над проектом с несколькими модулями maven и веб-проектами, которые зависят друг от друга. Я использую IntelliJ в качестве своей IDE для компиляции и запуска веб-проектов.

Я заметил, что вышеприведенное, похоже, больше не соответствует действительности, причина в том, что загружаемый файл теперь запекается в банку и развертывается в зависимости от веб-проекта. Я заметил это только после попытки изменить файл в моей целевой папке, но безрезультатно. Это создавало впечатление, что кеширование происходит.

2 голосов
/ 14 августа 2014

Class.getResources будет извлекать ресурс загрузчиком классов, который загружает объект.В то время как ClassLoader.getResource будет извлекать ресурс, используя указанный загрузчик классов.

0 голосов
/ 11 марта 2014

Я попытался прочитать из 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 часа на отладку этого ...: (

...