Я хотів би знати найкращий спосіб завантаження ресурсу на Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.
Я хотів би знати найкращий спосіб завантаження ресурсу на Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.Відповіді:
Розробіть рішення відповідно до того, що ви хочете ...
Є дві речі, які getResource
/ getResourceAsStream()
отримають з класу, на який він називається ...
Так що якщо ви робите
this.getClass().getResource("foo.txt");
вона спробує завантажити foo.txt з того ж пакету, що і клас "цей", і з завантажувачем класів класу "цей". Якщо ви поставите "/" спереду, то ви абсолютно посилаєтесь на ресурс.
this.getClass().getResource("/x/y/z/foo.txt")
буде завантажувати ресурс із завантажувача класів "this" та з пакета xyz (він повинен бути у тому ж каталозі, що і класи у цьому пакеті).
Thread.currentThread().getContextClassLoader().getResource(name)
завантажується завантажувачем контекстного класу, але не вирішує ім'я відповідно до будь-якого пакету (на нього має бути абсолютно посилання)
System.class.getResource(name)
Завантажить ресурс завантажувачем системного класу (на нього також слід посилатися, оскільки ви нічого не зможете помістити в пакет java.lang (пакет System).
Просто погляньте на джерело. Також вказується, що getResourceAsStream просто викликає "openStream" за URL-адресою, поверненою з getResource, і повертає її.
Thread#setContextClassLoader
. Це корисно, якщо вам потрібно змінити шлях класу під час виконання програми.
Що ж, це частково залежить від того, що ви хочете статися, якщо ви насправді в похідному класі.
Наприклад, припустимо SuperClass
в A.jar і SubClass
у B.jar, і ви виконуєте код у методі екземпляра, оголошеному в, SuperClass
але де this
посилається на екземпляр SubClass
. Якщо ви користуєтеся, this.getClass().getResource()
він виглядатиме відносно SubClass
, у B.jar. Я підозрюю, що зазвичай це не те, що потрібно.
Особисто я, мабуть, використовую Foo.class.getResourceAsStream(name)
найчастіше - якщо ви вже знаєте назву ресурсу, за яким ви шукаєте, і ви впевнені, де це стосується Foo
, це найбільш надійний спосіб зробити це ІМО.
Звичайно, бувають випадки, коли це не те, чого ти хочеш: оцінюй кожну справу по суті. Просто "я знаю, що цей ресурс є в комплекті з цим класом" - це найпоширеніший, з яким я стикався.
this.getClass()
. Створіть екземпляр підкласу та зателефонуйте до методу ... він надрукує ім'я підкласу, а не надклас.
Я шукаю три місця, як показано нижче. Коментарі вітаються.
public URL getResource(String resource){
URL url ;
//Try with the Thread Context Loader.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader != null){
url = classLoader.getResource(resource);
if(url != null){
return url;
}
}
//Let's now try with the classloader that loaded this class.
classLoader = Loader.class.getClassLoader();
if(classLoader != null){
url = classLoader.getResource(resource);
if(url != null){
return url;
}
}
//Last ditch attempt. Get the resource from the classpath.
return ClassLoader.getSystemResource(resource);
}
Я знаю, що насправді пізно для іншої відповіді, але я просто хотів поділитися тим, що мені допомогло наприкінці. Він також буде завантажувати ресурси / файли з абсолютного шляху файлової системи (не тільки класової).
public class ResourceLoader {
public static URL getResource(String resource) {
final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
classLoaders.add(Thread.currentThread().getContextClassLoader());
classLoaders.add(ResourceLoader.class.getClassLoader());
for (ClassLoader classLoader : classLoaders) {
final URL url = getResourceWith(classLoader, resource);
if (url != null) {
return url;
}
}
final URL systemResource = ClassLoader.getSystemResource(resource);
if (systemResource != null) {
return systemResource;
} else {
try {
return new File(resource).toURI().toURL();
} catch (MalformedURLException e) {
return null;
}
}
}
private static URL getResourceWith(ClassLoader classLoader, String resource) {
if (classLoader != null) {
return classLoader.getResource(resource);
}
return null;
}
}
Я спробував безліч способів і функцій, запропонованих вище, але вони не працювали в моєму проекті. У будь-якому випадку я знайшов рішення, і ось воно:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
this.getClass().getResourceAsStream()
в цьому випадку. Якщо ви подивитесь на джерело getResourceAsStream
методу, ви помітите, що він робить те саме, що і ви, але розумнішим способом (резервний запас, якщо його немає ClassLoader
в класі). Це також вказує на те, що ви можете зіткнутися з потенціалом null
на getClassLoader
в вашому коді ...
this.getClass().getResourceAsStream()
, не працює для мене, тому я використовую, що працює. Я думаю, що є такі люди, які можуть зіткнутися з такою проблемою, як моя.