2010-10-05 7 views

Respuesta

107

Calcular la solución de acuerdo a lo que quiere ...

Hay dos cosas que getResource/getResourceAsStream() se obtiene de la clase que se llama en ...

  1. El cargador de clases
  2. La ubicación inicial

Así que si lo hace

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

intentará cargar foo.txt desde el mismo paquete que la clase "this" y con el cargador de clase de la clase "this". Si coloca un "/" al frente, entonces está haciendo referencia absoluta al recurso.

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

cargará el recurso desde el cargador de clases de "este" y desde el paquete x.y.z (que tendrá que estar en el mismo directorio que las clases del paquete).

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

se carga con el cargador de clases de contexto, pero no va a resolver el nombre de acuerdo a cualquier paquete (se debe hacer referencia absoluta)

System.class.getResource(name) 

cargará el recurso con el cargador de clases del sistema (que sería tiene que ser referenciada absolutamente también, ya que no podrá poner nada en el paquete java.lang (el paquete de Sistema).

Solo eche un vistazo a la fuente.También indica que getResourceAsStream solo llama a "openStream" en la URL devuelta por getResource y lo devuelve.

+0

Los nombres de los paquetes AFAIK no importan, es el classpath del cargador de clases que sí lo es. –

+0

@Bart si observa el código fuente, notará que el nombre de la clase sí importa cuando llama a getResource en una clase. Lo primero que hace esta llamada es llamar a "resolveName", que agrega el prefijo del paquete, si corresponde. Javadoc for resolveName es "Agregar un prefijo de nombre de paquete si el nombre no es absoluto. Eliminar el encabezado"/"si el nombre es absoluto" –

+6

Ah, ya veo. Absoluto aquí significa relativo a la ruta de clase, en lugar del sistema de archivos absoluto. –

12

Bueno, depende en parte de lo que desea que suceda si usted es realmente en una clase derivada.

Por ejemplo, supongamos que está en SuperClass A.jar y SubClass está en B.jar, y ya está ejecutando el código en un método de instancia declarada en SuperClass pero donde this se refiere a una instancia de SubClass. Si usa this.getClass().getResource() se verá relativo a SubClass, en B.jar. Sospecho que es generalmente no es lo que se requiere.

Personalmente, probablemente usaría Foo.class.getResourceAsStream(name) con más frecuencia. Si ya conoce el nombre del recurso que busca y está seguro de dónde está relacionado con Foo, esa es la forma más robusta de hacerlo. IMO .

Por supuesto, hay veces en que eso es no lo que quiere, también: juzgar cada caso en función de sus méritos. Es solo el "Sé que este recurso está incluido con esta clase" es el más común que he encontrado.

+0

al plato: una duda en la afirmación "que está ejecutando el código en un método de instancia de SuperClass pero cuando esto se refiere a una instancia de la subclase" si está ejecutando declaraciones método de instancia interna de superclase, entonces "esto" se referirá a la superclase, no a la subclase. –

+0

@Suresh: No, no lo hará. ¡Intentalo! Cree dos clases, haciendo que una deriva del otro, y luego en la superclase imprima 'this.getClass()'. Cree una instancia de la subclase y llame al método ... imprimirá el nombre de la subclase, no la superclase. –

+0

Gracias método de instancia de subclase llama al método de superclase. –

8

Busco tres lugares como se muestra a continuación. Comentarios bienvenidos.

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

Gracias, esta es una gran idea. Justo lo que necesitaba. – devo

+1

Estaba viendo los comentarios en su código y el último parece interesante. ¿No se cargan todos los recursos del classpath? ¿Y qué casos cubriría ClassLoader.getSystemResource() que el anterior no tuvo éxito? – nyxz

+0

Honestamente, no entiendo por qué querría cargar archivos de 3 lugares diferentes. ¿No sabes dónde están almacenados tus archivos? – bvdb

1

Sé que realmente tarde para otra respuesta, pero yo sólo quería compartir lo que me ayudó al final. También cargará recursos/archivos de la ruta absoluta del sistema de archivos (no solo de la ruta de clases).

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

Probé muchas de las formas y funciones que sugerí anteriormente, pero no funcionaron en mi proyecto. De todas formas he encontrado solución y aquí está:

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

Debería usar 'this.getClass(). GetResourceAsStream()' en este caso. Si echas un vistazo al origen del método 'getResourceAsStream', notarás que hace lo mismo que tú pero de una manera más inteligente (alternativa si no se puede encontrar' ClassLoader' en la clase). También indica que puede encontrar un '' null' potencial en 'getClassLoader' en su código ... – PomCompot

+0

@PromCompot, como dije' this.getClass(). GetResourceAsStream() 'no funciona para mí, entonces lo uso. Creo que hay algunas personas que pueden enfrentar un problema como el mío. – Vladislav

Cuestiones relacionadas