logo

ClassLoader em Java

Carregador de classe Java

Java ClassLoader é uma classe abstrata. Pertence a um java.lang pacote. Carrega classes de diferentes recursos. Java ClassLoader é usado para carregar as classes em tempo de execução. Em outras palavras, a JVM executa o processo de vinculação em tempo de execução. As classes são carregadas na JVM de acordo com a necessidade. Se uma classe carregada depender de outra classe, essa classe também será carregada. Quando solicitamos o carregamento de uma classe, ele delega a classe ao seu pai. Dessa forma, a exclusividade é mantida no ambiente de tempo de execução. É essencial executar um programa Java.

java localdatahora
ClassLoader em Java

Java ClassLoader é baseado em três princípios: Delegação , Visibilidade , e Singularidade .

    Princípio de delegação:Ele encaminha a solicitação de carregamento de classe para o carregador de classe pai. Ele só carrega a classe se o pai não encontrar ou carregar a classe.Princípio de visibilidade:Ele permite que o carregador de classes filho veja todas as classes carregadas pelo ClassLoader pai. Mas o carregador de classes pai não pode ver as classes carregadas pelo carregador de classes filho.Princípio da singularidade:Permite carregar uma classe uma vez. Isso é alcançado pelo princípio da delegação. Ele garante que o ClassLoader filho não recarregue a classe, que já foi carregada pelo pai.

Tipos de ClassLoader

Em Java, cada ClassLoader possui um local predefinido de onde carregam os arquivos de classe. Existem os seguintes tipos de ClassLoader em Java:

Carregador de classes Bootstrap: Ele carrega arquivos de classe JDK padrão de rt.jar e outras classes principais. É pai de todos os carregadores de classe. Não tem nenhum pai. Quando chamamos String.class.getClassLoader() ele retorna nulo e qualquer código baseado nele lança NullPointerException. Também é chamado de ClassLoader Primordial. Ele carrega arquivos de classe de jre/lib/rt.jar. Por exemplo, classe de pacote java.lang.

Carregador de classes de extensões: Ele delega a solicitação de carregamento de classe ao seu pai. Se o carregamento de uma classe não for bem-sucedido, ele carrega as classes do diretório jre/lib/ext ou de qualquer outro diretório como java.ext.dirs. É implementado por sun.misc.Launcher$ExtClassLoader na JVM.

Carregador de classes do sistema: Ele carrega classes específicas do aplicativo da variável de ambiente CLASSPATH. Ele pode ser definido ao invocar o programa usando as opções de linha de comando -cp ou classpath. É filho da extensão ClassLoader. Ele é implementado pela classe sun.misc.Launcher$AppClassLoader. Todo Java ClassLoader implementa java.lang.ClassLoader.

ClassLoader em Java

Como funciona o ClassLoader em Java

Quando a JVM solicita uma classe, ela invoca um método loadClass() da classe java.lang.ClassLoader, passando o nome totalmente classificado da classe. O método loadClass() chama o método findLoadedClass() para verificar se a classe já foi carregada ou não. É necessário evitar carregar a classe várias vezes.

Se a classe já estiver carregada, ele delega a solicitação ao ClassLoader pai para carregar a classe. Se o ClassLoader não encontrar a classe, ele invoca o método findClass() para procurar as classes no sistema de arquivos. O diagrama a seguir mostra como o ClassLoader carrega classes em Java usando delegação.

ClassLoader em Java

Suponha que tenhamos uma classe Demo.class específica do aplicativo. A solicitação de carregamento dos arquivos desta classe é transferida para o Application ClassLoader. Ele delega ao seu pai Extension ClassLoader. Além disso, ele delega ao Bootstrap ClassLoader. Bootstrap pesquisa essa classe em rt.jar e já que essa classe não está lá. Agora solicite a transferência para o Extension ClassLoader que procura o diretório jre/lib/ext e tenta localizar esta classe lá. Se a classe for encontrada lá, o Extension ClassLoader carrega essa classe. O aplicativo ClassLoader nunca carrega essa classe. Quando a extensão ClassLoader não a carrega, o Aplicativo ClaasLoader a carrega de CLASSPATH em Java.

O princípio da visibilidade afirma que o ClassLoader filho pode ver a classe carregada pelo ClassLoader pai, mas vice-versa não é verdade. Isso significa que se o Application ClassLoader carregar Demo.class, nesse caso, tentar carregar Demo.class explicitamente usando a extensão ClassLoader lançará java.lang.ClassNotFoundException.

De acordo com o princípio da exclusividade, uma classe carregada pelo pai não deve ser carregada novamente pelo Child ClassLoader. Portanto, é possível escrever um carregador de classes que viole os princípios de delegação e exclusividade e carregue a classe por si só.

Resumindo, o carregador de classes segue a seguinte regra:

  • Verifica se a classe já está carregada.
  • Se a classe não estiver carregada, peça ao carregador de classe pai para carregar a classe.
  • Se o carregador de classes pai não puder carregar a classe, tente carregá-la neste carregador de classes.

Considere o seguinte exemplo:

 public class Demo { public static void main(String args[]) { System.out.println('How are you?'); } } 

Compile e execute o código acima usando o seguinte comando:

 javac Demo.java java -verbose:class Demo 

-verbose:classe: É usado para exibir informações sobre classes que estão sendo carregadas pela JVM. É útil ao usar o carregador de classes para carregar classes dinamicamente. A figura a seguir mostra a saída.

ClassLoader em Java

Podemos observar que as classes de tempo de execução exigidas pela classe da aplicação (Demo) são carregadas primeiro.

Quando as aulas são carregadas

Existem apenas dois casos:

  • Quando o novo código de bytes é executado.
  • Quando o código de bytes faz uma referência estática a uma classe. Por exemplo, Sistema.out .

Carregamento de classe estático vs. dinâmico

As classes são carregadas estaticamente com o operador 'novo'. O carregamento dinâmico de classes invoca as funções de um carregador de classes em tempo de execução usando o método Class.forName().

Diferença entre loadClass() e Class.forName()

O método loadClass() carrega apenas a classe, mas não inicializa o objeto. Enquanto o método Class.forName() inicializa o objeto após carregá-lo. Por exemplo, se você estiver usando ClassLoader.loadClass() para carregar o driver JDBC, o carregador de classes não permitirá carregar o driver JDBC.

O método java.lang.Class.forName() retorna o objeto de classe acoplado à classe ou faz interface com o nome da string fornecido. Ele lança ClassNotFoundException se a classe não for encontrada.

Exemplo

Neste exemplo, a classe java.lang.String é carregada. Ele imprime o nome da classe, o nome do pacote e os nomes de todos os métodos disponíveis da classe String. Estamos usando Class.forName() no exemplo a seguir.

Aula: Representa um objeto Class que pode ser de qualquer tipo (? é um curinga). O tipo Class contém metainformações sobre uma classe. Por exemplo, o tipo de String.class é Class. Use Class se a classe que está sendo modelada for desconhecida.

getDeclaredMethod(): Retorna uma matriz contendo objetos Method refletindo todos os métodos declarados da classe ou interface representada por este objeto Class, incluindo acesso público, protegido, padrão (pacote) e métodos privados, mas excluindo métodos herdados.

getNome(): Ele retorna o nome do método representado por este objeto Method, como uma String.

 import java.lang.reflect.Method; public class ClassForNameExample { public static void main(String[] args) { try { Class cls = Class.forName('java.lang.String'); System.out.println('Class Name: ' + cls.getName()); System.out.println('Package Name: ' + cls.getPackage()); Method[] methods = cls.getDeclaredMethods(); System.out.println('-----Methods of String class -------------'); for (Method method : methods) { System.out.println(method.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } 

Saída

 Class Name: java.lang.String Package Name: package java.lang -----Methods of String class ------------- value coder equals length toString hashCode getChars ------ ------ ------ intern isLatin1 checkOffset checkBoundsOffCount checkBoundsBeginEnd access0 access0