2010-10-05 12 views

Odpowiedz

107

wypracować rozwiązania według tego, co chcesz ...

Są dwie rzeczy, które getResource/getResourceAsStream() dostaną z klasy to nazywa się na ...

  1. Ładowarka klasa
  2. Pozycja początkowa

Więc jeśli nie

this.getClass().getResource("foo.txt"); 

spróbuje załadować plik foo.txt z tego samego pakietu co klasa "this" oraz z programu ładującego klasy "this" class. Jeśli umieścisz "/" z przodu, to bezwzględnie odwołasz się do zasobu.

this.getClass().getResource("/x/y/z/foo.txt") 

będzie załadować zasobu z ładowaczem klasy „to” i od pakietu x.y.z (to będzie musiał być w tym samym katalogu co klasach w tym pakiecie).

Thread.currentThread().getContextClassLoader().getResource(name) 

będzie ładować z ładowarki klasy kontekstu, ale nie rozwiąże nazwę według dowolnego pakietu (to musi być absolutnie odwoływać)

System.class.getResource(name) 

załaduje zasobu z ładowaczem systemu klasy (to byłoby muszą być bezwzględnie odwoływane, ponieważ nie będzie można umieścić niczego w pakiecie java.lang (pakiet System).

Wystarczy spojrzeć na źródło.Wskazuje również, że getResourceAsStream po prostu wywołuje "openStream" na URL zwróconym przez getResource i zwraca to.

+0

Nazwy pakietów AFAIK nie mają znaczenia, jest to ścieżka klasy programu ładującego klasy. –

+0

@Bart, jeśli spojrzysz na kod źródłowy, zauważysz, że nazwa klasy ma znaczenie, gdy wywołujesz getResource na klasie. Pierwszą rzeczą, jaką robi to wywołanie, jest wywołanie "resolveName", które dodaje prefiks pakietu, jeśli jest to właściwe. Javadoc dla resolveName to "Dodaj prefiks nazwy pakietu, jeśli nazwa nie jest bezwzględna Usuń wiodącą"/", jeśli nazwa jest absolutna" –

+6

Ah, widzę. Bezwzględny tutaj oznacza raczej względem ścieżki klasowej, a nie bezwzględny system plików. –

12

Cóż, częściowo zależy od tego, co chcesz zrobić, jeśli jesteś w rzeczywistości w klasie pochodnej.

Na przykład, załóżmy SuperClass w A.jar i SubClass jest w B.jar, a ty wykonywania kodu w metodzie instancji zadeklarowanej SuperClass ale gdzie this odnosi się do instancji SubClass. Jeśli użyjesz wartości this.getClass().getResource(), będzie ona wyglądać w stosunku do SubClass w pliku B.jar. Podejrzewam, że to nie jest wymagane, to jest .

Osobiście najczęściej używałbym Foo.class.getResourceAsStream(name) - jeśli znasz już nazwę szukanego zasobu i masz pewność, że jest on względny względem Foo, jest to najsolidniejszy sposób na wykonanie IMO .

Oczywiście są takie chwile, kiedy to nie co chcesz: oceniaj każdy przypadek na podstawie jego zalet. To tylko "Wiem, że ten zasób jest w pakiecie z tą klasą" jest najczęstszą, na którą natknąłem się.

+0

skeet: wątpliwości w zestawieniu „jesteś wykonywania kodu w metodzie instancji SuperClass ale gdzie ta odnosi się do instancji podklasy”, jeżeli jesteśmy wykonywania instrukcji wewnątrz instancji metoda super klasy, wtedy "to" będzie odnosiło się do nadklasy nie do podklasy. –

+0

@Suresh: Nie, nie będzie. Spróbuj! Utwórz dwie klasy, dzięki czemu jedna wywodzi się od drugiej, a następnie w nadklasie wypisz 'this.getClass()'. Utwórz instancję podklasy i wywołaj metodę ... wypisze nazwę podklasy, a nie nadklasę. –

+0

dzięki metodzie instancji podklasy wywołuje metodę nadklasy. –

8

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); 
} 
+0

Dzięki, to świetny pomysł. Dokładnie to, czego potrzebowałem. – devo

+1

Patrzyłem na komentarze w twoim kodzie, a ostatni brzmi interesująco. Czy nie wszystkie zasoby są ładowane ze ścieżki klasy? A jakie przypadki pokrywa ClassLoader.getSystemResource(), że powyższe nie powiodło się? – nyxz

+0

Szczerze mówiąc, nie rozumiem, dlaczego chciałbyś załadować pliki z 3 różnych miejsc. Nie wiesz, gdzie są przechowywane twoje pliki? – bvdb

1

Wiem, że naprawdę późno na inną odpowiedź, ale chciałem podzielić się tym, co pomogło mi na końcu. Będzie również ładował zasoby/pliki z absolutnej ś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; 
    } 

} 
-1

Próbowałem wiele sposobów i funkcji sugerowanych powyżej, ale nie działały one w moim projekcie. W każdym razie znalazłem rozwiązanie i to jest tutaj:

try { 
    InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png"); 
    img = ImageIO.read(path); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
+0

Powinieneś lepiej użyć 'this.getClass(). GetResourceAsStream()' w tym przypadku. Jeśli spojrzysz na źródło metody 'getResourceAsStream', zauważysz, że robi to samo, ale w bardziej inteligentny sposób (awaryjne, jeśli na klasie nie znaleziono klasy" ClassLoader "). Wskazuje również, że możesz napotkać potencjalny 'null' na' getClassLoader' w twoim kodzie ... – PomCompot

+0

@PromCompot, jak powiedziałem 'this.getClass(). GetResourceAsStream()' nie działa dla mnie, więc używam tego działa. Sądzę, że są ludzie, którzy mogą stawić czoła problemom, takim jak mój. – Vladislav

Powiązane problemy