Ах, это один из моих любимых предметов. Существуют два способа загрузки ресурса через classpath:
Class.getResourceAsStream(resource)
и
ClassLoader.getResourceAsStream(resource)
(есть и другие способы, которые включают аналогичное получение URL-адреса ресурса, а затем открытие соединения с ним, но это два прямых способа).
Первый метод фактически делегирует второму после искажения имени ресурса. Существуют два вида имен ресурсов: абсолютные (например, «/ path / to / resource / resource») и относительные (например, «resource»). Абсолютные пути начинаются с "/".
Вот пример, который должен иллюстрировать. Рассмотрим класс com.example.A. Рассмотрим два ресурса, один из которых расположен в / com / example / nested, а другой - в / top, в пути к классам. Следующая программа показывает девять возможных способов доступа к двум ресурсам:
package com.example;
public class A {
public static void main(String args[]) {
// Class.getResourceAsStream
Object resource = A.class.getResourceAsStream("nested");
System.out.println("1: A.class nested=" + resource);
resource = A.class.getResourceAsStream("/com/example/nested");
System.out.println("2: A.class /com/example/nested=" + resource);
resource = A.class.getResourceAsStream("top");
System.out.println("3: A.class top=" + resource);
resource = A.class.getResourceAsStream("/top");
System.out.println("4: A.class /top=" + resource);
// ClassLoader.getResourceAsStream
ClassLoader cl = A.class.getClassLoader();
resource = cl.getResourceAsStream("nested");
System.out.println("5: cl nested=" + resource);
resource = cl.getResourceAsStream("/com/example/nested");
System.out.println("6: cl /com/example/nested=" + resource);
resource = cl.getResourceAsStream("com/example/nested");
System.out.println("7: cl com/example/nested=" + resource);
resource = cl.getResourceAsStream("top");
System.out.println("8: cl top=" + resource);
resource = cl.getResourceAsStream("/top");
System.out.println("9: cl /top=" + resource);
}
}
Вывод из программы:
1: A.class nested=java.io.BufferedInputStream@19821f
2: A.class /com/example/nested=java.io.BufferedInputStream@addbf1
3: A.class top=null
4: A.class /top=java.io.BufferedInputStream@42e816
5: cl nested=null
6: cl /com/example/nested=null
7: cl com/example/nested=java.io.BufferedInputStream@9304b1
8: cl top=java.io.BufferedInputStream@190d11
9: cl /top=null
В основном вещи делают то, что вы ожидаете. Случай 3 завершается неудачно, поскольку относительное разрешение класса относится к классу, поэтому «top» означает «/ com / example / top», а «/ top» означает то, что говорится.
Case-5 завершается неудачно, потому что относительное разрешение загрузчика классов относится к загрузчику классов. Но неожиданно Case-6 также дает сбой: можно ожидать, что «/ com / example / nested» разрешится правильно. Чтобы получить доступ к вложенному ресурсу через загрузчик классов, вам нужно использовать Case-7, то есть вложенный путь относительно корня загрузчика классов. Аналогичным образом, Case-9 дает сбой, но Case-8 проходит.
Помните: для java.lang.Class, getResourceAsStream () делегирует загрузчику классов:
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
так что важно поведение resolName ().
Наконец, поскольку поведение загрузчика классов загружает класс, который по существу управляет getResourceAsStream (), а загрузчик классов часто является пользовательским загрузчиком, правила загрузки ресурсов могут быть еще более сложными. например для веб-приложений загружайте из WEB-INF / classes или WEB-INF / lib в контексте веб-приложения, но не из других изолированных веб-приложений. Кроме того, хорошо ведущие себя загрузчики классов делегируют родителям, так что дублированные ресурсы в пути к классам могут быть недоступны при использовании этого механизма.