Configurando Java #2: O que são as variáveis JAVA_HOME, PATH e CLASSPATH
As variáveis JAVA_HOME, PATH e CLASSPATH são três importantes variáveis relacionadas ao ambiente Java.
1 - O que são variáveis de ambiente?
As variáveis de ambiente são variáveis do sistema acessíveis por todos os processos em execução no sistema operacional (SO). As variáveis de ambiente são úteis para armazenar valores referente ao sistema, como os diretórios para procurar os programas executáveis (PATH) e a versão do sistema operacional. As variáveis também armazenam informações que são úteis para diversos programas.
Exemplos de variáveis de ambiente no sistema operacional Windows:
- COMPUTERNAME, USERNAME: armazena o nome do computador e do usuário atual;
- OS: indica o sistema operaciona;
- SystemRoot: Indica o caminho raíz do windows.
- PATH: armazena a lista de diretórios onde deve ser procurado os programas executáveis.
Para visualizar o valor de uma variável de ambiente no Windows podemos usar o comando “echo %VARIAVEL%” no CMD, onde VARIAVEL deve ser substituído pelo nome da variável, exemplo, ao digitar o comando “echo %SystemRoot%” será impresso o valor “C:\WINDOWS”:
Exemplo de variáveis de ambiente no sistema operacional Linux:
- USER: indica o usuário logado;
- HOME: indica o diretório home do usuário atual;
- PATH: armazena a lista de diretórios onde deve ser procurado os programas executáveis.
Para visualizar o valor de uma variável no ambiente do Linux podemos usar o comando “printenv VARIAVEL” no terminal, onde VARIAVEL deve ser substituído pelo nome da variável, exemplo, ao digitar o comando “printenv HOME”, será impresso o valor “/home/mint”:
2 - Níveis de variáveis
As variáveis de ambiente são classificadas em três níveis: local, de usuário e global.
2.1 - Variáveis locais
As variáveis locais são variáveis que irão existir somente enquanto o terminal estiver aberto, a partir do comento que o terminal for fechado, as variáveis deixam de existir.
2.2 - Variáveis de usuário
Variáveis de usuário são variáveis que são visíveis somente para o usuário atual logado no sistema operacional.
2.3 - Variáveis globais
As variáveis globais são variáveis que são visíveis para todos os usuários e processos do sistema operacional.
3 - O que é a variável JAVA_HOME?
A variável JAVA_HOME é a variável que indica o caminho de instalação do JDK, em uma tradução literal seria o “lar do java”. Ela será necessária para utilizarmos os recursos do JDK como o“javac” (comando para chamar o compilador java) no terminal sem precisar especificar em que lugar o JDK está instalado.
Como vimos no post sobre instalação do JDK no Windows, no tópico 7 - Extra: Como confirmar se a instalação deu certo?, após finalizar a instalação não é possível executar o comando “javac -version” diretamente no terminal pois o sistema operacional não sabe o que é “javac”. Para o sistema saber onde está o executável do é “javac”, é necessário configurar o JAVA_HOME com o caminho de instalação do JDK e depois adicionar o JAVA_HOME na variável PATH seguido da pasta bin, pois é dentro da pasta bin que o executável do compilador está localizado. Veremos isso no tópico a seguir sobre a variável PATH. Após configurar o JAVA_HOME e editar o PATH, é possível executar diretamente no terminal o comando “javac -version”.
4 - O que é a variável PATH?
A variável PATH é uma variável onde é configurado uma lista de diretórios/pastas em que o sistema operacional deve procurar os programas executáveis.
No início desse post, a variável PATH foi utilizada como exemplo de variável que existe tanto no Windows quanto no Linux. Ambos os sistemas operacionais utilizam a mesma lógica para encontrar os programas executáveis, ao digitar o nome de um programa no terminal, o sistema operacional irá procurar na variável PATH, em qual dos diretórios/caminhos aquele programa está disponível, e no momento que encontrar, irá executar aquele programa.
A busca também é feita da mesma forma em ambos os sistemas operacionais, vai percorrer a lista de diretórios/pastas da esquerda para a direita e rodar o primeiro programa que encontrar. Exemplo: Se configurar duas versões do Java, ao rodar o comando “java -version” ou “javac -version”, o sistema operacional irá executar a versão do Java de acordo com que o estiver configurado primeiro (mais a esquerda) na lista da variável PATH.
Obs: A variável PATH não necessariamente precisa ser configurada, só que caso não seja configurada, haverá o incomodo de sempre que necessitar executar comandos como java.exe, javac.exe, jvisualvm.exe ou javadoc.exe, ser necessário utilizar o diretório completo de onde encontram-se esses arquivos. Isso obviamente não é o que queremos, por isso vale destacar que não é uma configuração obrigatória, mas é recomendada.
5 - O que é a variável CLASSPATH?
A variável CLASSPATH é uma variável específica utilizada pelo Java para indicar o local em que as classes devem ser procuradas pelo carregador de classes ao compilar ou executar um programa. Essas classes normalmente são disponibilizadas em arquivos com extensão .jar. O uso do classpath ocorre por meio do parâmetro -cp ou -classpath por linha de comando, ou pela configuração de uma variável de ambiente com o nome CLASSPATH.
É necessário entender como funciona a busca de classes do Java para entender a variável de ambiente CLASSPATH.
A ordem em que o carregador de classes do Java procura as classes para compilar ou executar um programa pode ser encontrada na documentação aqui, e descrevo abaixo:
- 1 - Classes da plataforma Java (bootstrap): são todas as classes incluídas na plataforma Java, ou seja, os pacotes iniciados com java.* e javax.*, além de bibliotecas como i18n.jar (classes de internacionalização), charsets.jar e outras. Essas classes são encontradas automaticamente e não é necessário configurá-las em nenhum lugar (Apesar de carregadas automaticamente, é possível alterar o local de onde as classes base do Java são carregadas, mas isso é extremamente raro de ser necessário, se você deseja saber como fazer saber isso, pode ver mais detalhes na documentação referenciada acima).
- 2 - Diretório de extensão: a JVM procura por classes presentes no diretório de extensão, esse diretório pode ser usado copiando classes externas e colocando-as no caminho de instalação do JRE, como exemplo “C:\Program Files\Java\jre1.8.0_241\lib\ext”. As classes de extensão devem estar encontradas em arquivos .jar.
- 3 - Classes de usuário (classpath): São detalhadas abaixo. Esse é o último passo que a JVM usa para procurar as classes e existem algumas regras de sobrescrita que deve-se tomar cuidado.
- 3.1 - Quando não existe nada configurado: primeiramente a busca é feita no diretório atual do programa executado, ou seja “.” (quando não é configurado a variável classpath nas variáveis de ambiente ou na linha de comando, a JVM assume o diretório atual do programa sendo executado como o diretório padrão para o classpath).
- 3.2 - Quando a variável CLASSPATH é configurada nas variáveis de ambiente: Caso exista configurada a variável CLASSPATH nas varia´veis de ambiente, essa variável irá sobrescrever o classpath default “.”. Por esse motivo é importante ao configurar o classpath por meio da variável de ambiente, adicionar “.” para que as classes do diretório atual do programa sejam encontradas (caso isso não seja feito o programa pode não funcionar pois a classe de inicialização da aplicação que está na pasta atual “.”, não será encontrada).
- 3.3 - Com o parâmetro “-cp ou -classpath” na linha de comando: quando é especificado por linha de comando o caminho das classes, essa configuração sobrescreve a variável de ambiente CLASSPATH. É possível utilizar tanto -cp quanto -classpath, ambos os comandos fazem a mesma coisa.
- 3.4 - Executando .jar e configurando o arquivo Manifest.MF: por último, ao executar um programa por meio de um arquivo .jar com o parâmetro “-jar” na linha de comando, pode existir configurado dentro do arquivo “.jar” um arquivo chamado Manfest.MF com configuração do classpath desse jar, quando isso acontecer, essa configuração dentro do .jar irá sobrescrever as configurações anteriores de linha de comando ou da variável de ambiente.
No próximo tópico, será visto o uso da opção “-verbose” que permite visualizar o carregamento das classes ao compilar ou executar um programa Java.
6 Bônus: Entendendo um pouco mais além como funciona o carregamento de classes e o classpath (prática)
A ordem do carregamento de classes do java é o mesmo para o processo de compilação e de execução de um programa. Nos exemplos a seguir, será mostrado o uso do carregamento de classe por meio de classes de extensão e por meio do classpath (padrão, por parâmetro -cp e por variável de ambiente CLASSPATH).
Será utilizado o parâmetro -verbose que mostra as classes carregadas.
Uma observação antes de iniciar os tópicos abaixo, é que quando me refiro ao processo de “compilação de um programa java”, estou me referindo ao uso do comando “javac” no terminal, que é o compilador java, uma das ferramentas de desenvolvimento do JDK, quando me refiro a “executar um programa java”, estou me referindo a usar o comando “java” no terminal, que é um dos comandos do JRE.
6.1 Processo de compilação
Veremos primeiro o uso das classes de extensão e classpath no processo de compilação.
6.1.1 Processo de compilação: classe de extensão
Como as classes de extensão devem ser distribuídas por meio de arquivos .jar, teremos uma classe chamada ExternalHello no pacote com.external, essa classe foi compilada e colocada dentro de um arquivo .jar chamado ExternalHello.jar, esse .jar será usado no exemplo:
A classe ExternalHello que está dentro do arquivo .jar será usada na classe SayHello:
- Primeiro, deve-se colocar o ExternalHello.jar dentro da pasta “C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext”:
- Feito isso, devemos compilar a classe SayHello.java com o comando “javac SayHello.java -verbose”.
Conforme por ser visto na saída mostrada no console acima, o compilador Java encontrou normalmente a classe ExternalHello nas classes de extensão, ou seja, no arquivo “C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\ExternalHello.jar”.
Obs: O caminho de extensão que o compilador vai encontrar as classes é o caminho de extensão do JRE privado (dentro da pasta do JDK), e não do JRE público. Lembre-se que nesta etapa está sendo visto o processo de COMPILAÇÃO de um programa java, onde é usado o JDK.
6.1.2 Processo de compilação: classpath default
Agora, faremos o teste prático do processo de compilação usando o classpath default. A diferença aqui, é que as classes serão procuradas diretamente, ou seja, os arquivos .class, e não dentro de arquivos .jar. É possível usar arquivos .jar referenciando-os no classpath personalizado nas variáveis de ambiente (CLASSPATH) ou por linha de comando (-cp ou -classpath), mas para isso é obrigatório indicar o nome do arquivo .jar em que a classe está localizada. Como o classpath default conta somente com o diretório atual “.” e nada mais, então não é possível colocar um arquivo “.jar” no mesmo diretório da classe compilada e esperar que essa classe seja encontrada.
Primeiro iremos ver que ao compilar um programa Java, os demais arquivos que fazem parte desse programa também são compilados juntos:
- Como mostrado na imagem abaixo, temos o código de ambas as classes usadas no programa, ambos os arquivos .java ainda não foram compilados:
- Nesse caso, ao compilar o arquivo SayHello.java com o comando “javac SayHello.java”, o compilador irá encontrar o arquivo ExternalHello.java e irá compilar junto, criando o respectivo .class para cada classe:
- Se verificar na saída do console com a opção -verbose, a classe ExternalHello.java irá aparecer no processo de compilação:
Ok, ambas as classes não estavam compiladas ainda, mas agora, se excluirmos o arquivo ExternalHello.java e deixarmos somente o arquivo ExternalHello.class, o compilador irá encontrar a classe por meio da busca de classes no classpath default que é o diretório atual “.”. Abaixo o exemplo:
Usando o comando “javac SayHello.java -verbose”, ao verificar na saída do console, a classe ExternalHello.class ainda será encontrada pois a sua referência está no classpath default (diretório atual), com isso, somente a classe SayHello.java foi compilada, e a classe ExternalHello.class foi encontrada pelo carregador de classes.
6.1.3 Processo de compilação: CLASSPATH nas variáveis de ambiente
O classpath configurado nas variáveis de ambiente do sistema operacional irá sobrescrever o classpath padrão que é o diretório atual de onde a classe está sendo compilada.
Os resultados serão os mesmos apresentados no item anterior 6.1.2 acima, e a diferença é que aqui é possível referenciar arquivos .jar. Abaixo exemplo de ambos os casos.
- Foi criado uma pasta chamada “libs” no Desktop e colocado dentro dela a classe “com\external\ExternalHello.class”:
- Foi configurado a variável de ambiente CLASSPATH:
- A classe SayHello foi deixada isolada:
- A classe foi compilada com o comando “javac SayHello.java -verbose”. Veja que na saída do console, o carregador de classe irá encontrar a classe externa por meio do caminho de referência (pasta “libs” no desktop) que foi configurado na variável de ambiente CLASSPATH:
IMPORTANTE: Caso o programa contivesse outras classes referenciadas e essas classes referenciadas estivessem no caminho padrão “.”, ao sobrescrever o classpath default por uma variável de ambiente, se na variável de ambiente o caminho padrão “.” não for incluído, as classes do caminho padrão não serão mais encontradas. Veja que no exemplo a variável CLASSPATH foi configurada iniciando com o caminho padrão “.” e depois com a pasta “libs” no desktop.
Agora vamos usar o arquivo .jar, colocamos o arquivo na mesma pasta “libs”:
Alteramos a variável de ambiente CLASSPATH e indicamos onde está o .jar:
Compilamos o programa com o comando “javac SayHello.java -verbose”. Veja que no console abaixo, a classe externa foi encontrada no arquivo .jar referenciado na variável de ambiente CLASSPATH:
6.1.4 Processo de compilação: parâmetro -cp ou -classpath
Ao usar o parâmetro por linha de comando para indicar o local onde as classes estão localizadas, a variável de ambiente CLASSPATH será sobrescrita.
Partindo do exemplo anterior, pegamos a pasta “libs” que foi criada no desktop e colocamos essa pasta no mesmo caminho onde está a classe SayHello para ser compilada.
Agora, executamos por linha de comando e informamos na linha de comando o classpath com parâmetro -cp: “javac -cp “.\libs” SayHello.java -verbose”. O console irá nos mostrar que a classe foi carregada da pasta de acordo com o caminho informado na linha de comando, ou seja, “.\libs\com\external\ExternalHello.class”:
6.2 Processo de execução de um programa
Não há diferença quando ao uso do classpath no processo de compilação e execução de um programa Java, vimos no tópico 6.1, os exemplos de carregamento de classe ao compilar um programa Java, então não será mostrado esses exemplos nesse tópico pois os resultados são os mesmos, somente será mostrado a diferença ao usar classes de extensão e será mostrado um exemplo do uso do classpath ao distribuir um programa java por meio de um arquivo .jar executável.
6.2.1 Processo de execução de um programa: classe de extensão
O processo para usar classe de extensão para executar um programa Java, é o mesmo usado no de compilação, a diferença é que ao compilar um programa Java, as classes de extensão devem ser colocadas dentro do JRE privado que está dentro do JDK, enquanto ao executar um programa Java, as classes de extensão devem estar dentro do JRE público.
Exemplo dos caminhos:
Para compilação: C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext
Para execução: C:\Program Files\Java\jre1.8.0_241\lib\ext
Note que para o processo de compilação, há um JRE que fica dentro da pasta do JDK. Ao compilar um programa com o comando “javac”, as classes de extensão serão buscadas nesse JRE dentro do JDK, ao executar um programa com o comando “java”, as classes de extensão serão buscadas dentro do JRE padrão, que é usado apenas para executar os programas.
6.2.2 Processo de execução de um programa: classpath default
O classpath default irá funcionar da mesma forma no processo de compilação e execução de um programa, as classes referenciadas pelo programa deverão estar disponíveis a partir do diretório padrão “.”. Como não é possível usar .jar no classpath padrão “.”, é obrigatório ter todos os arquivos .class disponíveis.
6.2.3 Processo de execução de um programa: CLASSPATH nas variáveis de ambiente
Ao usar a variável de ambiente CLASSPATH, o comportamento é o mesmo para o processo de compilação e execução de um programa.
6.2.4 Processo de execução de um programa: parâmetro -cp ou -classpath
Ao usar o classpath por meio da linha de comando, o comportamento também é o mesmo para o processo de compilação e execução de um programa.
6.2.5 Processo de execução de um programa: Class-Path configurado dentro de um .jar distribuído como um programa
Além das possibilidades vistas até aqui para executar um programa com o arquivo .class compilado, existe a possibilidade de executar um programa Java por meio de um arquivo .jar executável, e dentro desse arquivo .jar é possível indicar onde está localizado o classpath. Quando esse classpath é configurado, os outros classpath são sobrescritos (padrão, por variável de ambiente e por linha de comando).
Será criado um arquivo .jar executável para configurar o classpath dentro do arquivo Manifest.mf.
- Primeiramente, colocamos o arquivo ExternalHello.jar já usado nos exemplos anteriores dentro da pasta “libs”:
- Compilamos o arquivo SayHello com o comando “javac -cp “.\libs\ExternalHello.jar” SayHello.java”:
- Agora, criamos um arquivo chamado Manifest.mf e incluímos o conteúdo abaixo dentro do arquivo (o arquivo deve ter uma linha em branco no final para funcionar):
Main-Class: SayHello
Class-Path: .\libs\ExternalHello.jar
- Por fim cria-se o arquivo “.jar” com o comando “jar -cfm SayHello.jar Manifest.mf SayHello.class”, e deixamos somente os arquivos necessários para execução do programa:
Ao executamos o jar com o comando “java -verbose -jar SayHello.jar”. Ao verificar no console, é possível ver que a classe externa foi carregada a partir do arquivo .jar configurado no arquivo manifest:
Veja também:
Os demais tutoriais da série podem ser acessados nos links abaixo:
- Série Configurando Java: Overview
- Configurando Java #1: Instalação do JRE e JDK no Windows
- Configurando Java #2: O que são as variáveis JAVA_HOME, PATH E CLASSPATH
- Configurando Java #3: Como configurar as variáveis JAVA_HOME, PATH E CLASSPATH no Windows