O Mecanismo de Carregamento de Classes em Java

O carregamento de classes em Java envolve a leitura de arquivos .class em formato binário para a área de dados do tempo de execução (método), criando um objeto Java.lang.Class na região de heap. Esse objeto encapsula os dados da classe na área de método e fornece interfaces para acesso aos dados.

Existem várias formas de carregar classes:

  1. Diretamente do sistema local
  2. Baixar .class via rede
  3. Carregar de arquivos zip/jar
  4. Extrair de bancos de dados especializados
  5. Compilar dinamicamente .java para .class (servidores)

O processo de carregamento é dividido em três etapas: carregamento, ligação e inicialização. A ligação inclui:

  • Validação: Garante a corretude da classe
  • Preparação: Aloca memória para variáveis estáticas
  • Resolução: Converte referências simbólicas em referências diretas

A inicialização atribui valores reais às variáveis estáticas. Por exemplo, para private static int a = 10, a sequência é: a=0 (padrão) → a=10 (inicialização).

A ordem de inicialização é: ( variáveis estáticas, blocos estáticos ) > ( variáveis, blocos de inicialização ) > construtor

A hierarquia de carregadores inclui:

  1. Carregador Bootstrap: Implementado em C++, carrega bibliotecas core como rt.jar
  2. Carregador de Extensão: Carrega classes de JAVA_HOME/jre/lib/ext
  3. Carregador de Aplicativo: Carrega classes do classpath
  4. Carregador Personalizado: Implementado por frameworks como Tomcat

O modelo de delegação garante que:

  • O carregador verifica primeiro em seu pai
  • Evita carregamento duplicaod
  • Previne substituição de classes críticas

Para obter a hierarquia de carregadores:

ClassLoader carregador = TesteCarregadorClasse.class.getClassLoader();
while(carregador != null) {
    System.out.println(carregador);
    carregador = carregador.getParent();
}

A verificação de igualdade entre classes requer:

  • Nome da classe idêntico
  • Mesmo carregador

Para garantir carregamento único, o método loadClass implementa:

protected synchronized Class<?> loadClass(String nomeClasse, boolean resolve)
    throws ClassNotFoundException {
    // Verifica se já foi carregado
    Class<?> classe = findLoadedClass(nomeClasse);
    if (classe == null) {
        try {
            if (parent != null) {
                classe = parent.loadClass(nomeClasse, false);
            } else {
                classe = findBootstrapClass0(nomeClasse);
            }
        } catch (ClassNotFoundException e) {
            classe = findClass(nomeClasse);
        }
    }
    if (resolve) {
        resolveClass(classe);
    }
    return classe;
}

Implementação de carregador personalizado:

public class MeuCarregador extends ClassLoader {
    protected Class<?> findClass(String nomeClasse) {
        byte[] bytes = lerBytesDaFonte(nomeClasse);
        return defineClass(nomeClasse, bytes, 0, bytes.length);
    }

    private byte[] lerBytesDaFonte(String nomeClasse) {
        // Lógica para obter bytes da classe
    }
}

Tags: classloaders JVM classloading custom-classloader

Publicado em 8-26 04:36