Chciałbym poznać najlepszy sposób ładowania zasobu w Javie:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.
Chciałbym poznać najlepszy sposób ładowania zasobu w Javie:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.Odpowiedzi:
Opracuj rozwiązanie zgodnie z tym, co chcesz ...
Są dwie rzeczy, które getResource
/ getResourceAsStream()
otrzyma od klasy, do której się odwołuje ...
Więc jeśli tak
this.getClass().getResource("foo.txt");
spróbuje załadować foo.txt z tego samego pakietu co klasa „this” oraz z programem ładującym klasy „this”. Jeśli umieścisz znak „/” na początku, odwołujesz się do zasobu.
this.getClass().getResource("/x/y/z/foo.txt")
załaduje zasób z programu ładującego klasy „this” iz pakietu xyz (będzie musiał znajdować się w tym samym katalogu, co klasy w tym pakiecie).
Thread.currentThread().getContextClassLoader().getResource(name)
załaduje się za pomocą programu ładującego klasy kontekstu, ale nie rozwiąże nazwy zgodnie z żadnym pakietem (musi być bezwzględnie przywoływany)
System.class.getResource(name)
Załaduje zasób za pomocą programu ładującego klasy systemowe (musiałby również być bezwzględnie odwołany, ponieważ nie będziesz w stanie umieścić niczego w pakiecie java.lang (pakiet System).
Spójrz tylko na źródło. Wskazuje również, że getResourceAsStream po prostu wywołuje „openStream” w adresie URL zwróconym przez getResource i zwraca go.
Thread#setContextClassLoader
. Jest to przydatne, jeśli chcesz zmodyfikować ścieżkę klasy podczas wykonywania programu.
Cóż, częściowo zależy to od tego, co chcesz, aby się wydarzyło, jeśli faktycznie jesteś w klasie pochodnej.
Na przykład załóżmy, że SuperClass
znajduje się w A.jar i SubClass
B.jar, a wykonujesz kod w metodzie instancji zadeklarowanej w, SuperClass
ale gdzie this
odnosi się do wystąpienia SubClass
. Jeśli używasz this.getClass().getResource()
, będzie wyglądać w stosunku do SubClass
, w B.jar. Podejrzewam, że zwykle nie jest to wymagane.
Osobiście prawdopodobnie Foo.class.getResourceAsStream(name)
używałbym najczęściej - jeśli znasz już nazwę zasobu, którego szukasz, i jesteś pewien, gdzie jest ona w stosunku do Foo
, jest to najbardziej solidny sposób zrobienia tego IMO.
Oczywiście są chwile, kiedy nie tego też chcesz: oceniaj każdy przypadek na podstawie jego meritum. To po prostu „Wiem, że ten zasób jest dołączony do tej klasy” jest najczęstszym, na jaki się natknąłem.
this.getClass()
. Utwórz instancję podklasy i wywołaj metodę ... wydrukuje nazwę podklasy, a nie nadklasy.
Przeszukuję trzy miejsca, jak pokazano poniżej. Komentarze mile widziane.
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);
}
Wiem, że jest naprawdę późno na inną odpowiedź, ale chciałem tylko podzielić się tym, co pomogło mi na końcu. Załaduje również zasoby / pliki z bezwzględnej ścieżki systemu plików (nie tylko ścieżki klas).
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;
}
}
Wypróbowałem wiele sposobów i funkcji, które zasugerowałem powyżej, ale nie zadziałały w moim projekcie. Tak czy inaczej znalazłem rozwiązanie i oto jest:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
this.getClass().getResourceAsStream()
tym przypadku powinieneś lepiej użyć . Jeśli przyjrzysz się źródłu getResourceAsStream
metody, zauważysz, że robi to samo co ty, ale w sprytniejszy sposób (jeśli nie ClassLoader
można znaleźć w klasie). Wskazuje również, że można napotkać potencjał null
na getClassLoader
w kodzie ...
this.getClass().getResourceAsStream()
nie działa dla mnie, więc używam tego. Myślę, że są ludzie, którzy mogą zmierzyć się z takim problemem jak mój.