Gostaria de saber a melhor forma de carregar um recurso em Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.
Gostaria de saber a melhor forma de carregar um recurso em Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.Respostas:
Encontre a solução de acordo com o que você deseja ...
Há duas coisas que getResource
/ getResourceAsStream()
obterá da classe em que é chamado ...
Então se você fizer
this.getClass().getResource("foo.txt");
ele tentará carregar foo.txt do mesmo pacote da classe "this" e com o carregador de classes da classe "this". Se você colocar um "/" na frente, estará fazendo uma referência absoluta ao recurso.
this.getClass().getResource("/x/y/z/foo.txt")
irá carregar o recurso do carregador de classes de "this" e do pacote xyz (ele precisará estar no mesmo diretório que as classes desse pacote).
Thread.currentThread().getContextClassLoader().getResource(name)
irá carregar com o carregador de classes de contexto, mas não resolverá o nome de acordo com qualquer pacote (deve ser absolutamente referenciado)
System.class.getResource(name)
Carregará o recurso com o carregador de classes do sistema (também teria que ser absolutamente referenciado, pois você não poderá colocar nada no pacote java.lang (o pacote de System).
Basta dar uma olhada na fonte. Também indica que getResourceAsStream apenas chama "openStream" no URL retornado de getResource e retorna isso.
Thread#setContextClassLoader
. Isso é útil se você precisar modificar o caminho de classe enquanto o programa está sendo executado.
Bem, isso depende parcialmente do que você deseja que aconteça se estiver realmente em uma classe derivada.
Por exemplo, suponha que SuperClass
está em A.jar e SubClass
em B.jar, e você está executando o código em um método de instância declarado em, SuperClass
mas onde this
se refere a uma instância de SubClass
. Se você usá- this.getClass().getResource()
lo, terá uma aparência relativa a SubClass
, em B.jar. Eu suspeito que geralmente não é o que é necessário.
Pessoalmente, eu provavelmente usaria com Foo.class.getResourceAsStream(name)
mais frequência - se você já sabe o nome do recurso que está procurando e tem certeza de onde ele está relacionado Foo
, essa é a maneira mais robusta de fazê-lo IMO.
É claro que há momentos em que você também não quer isso: julgue cada caso pelos seus méritos. É apenas o "Eu sei que este recurso vem junto com esta classe" é o mais comum que encontrei.
this.getClass()
. Crie uma instância da subclasse e chame o método ... ele imprimirá o nome da subclasse, não da superclasse.
Eu procuro três lugares como mostrado abaixo. Comentários são bem-vindos.
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);
}
Eu sei que é muito tarde para outra resposta, mas eu só queria compartilhar o que me ajudou no final. Ele também carregará recursos / arquivos do caminho absoluto do sistema de arquivos (não apenas do caminho de classe).
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;
}
}
Tentei várias maneiras e funções sugeridas acima, mas não funcionaram no meu projeto. De qualquer forma, encontrei a solução e aqui está:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
this.getClass().getResourceAsStream()
neste caso. Se você getResourceAsStream
der uma olhada na fonte do método, notará que ele faz a mesma coisa que você, mas de uma forma mais inteligente (fallback se nenhum ClassLoader
for encontrado na classe). Ele também indica que você pode encontrar um potencial null
em getClassLoader
em seu código ...
this.getClass().getResourceAsStream()
não está funcionando para mim, então eu uso isso funciona. Acho que existem algumas pessoas que podem enfrentar problemas como o meu.