Java JDK, JRE e JVM
Três siglas aparecem em todo lugar quando o assunto é Java: JDK, JRE e JVM. Elas são peças encaixadas uma dentro da outra, e saber qual é qual evita o erro mais comum de quem instala o Java pela primeira vez: ter o Java para rodar programas, mas não para criar. Nesta aula você abre o JDK, olha o bytecode de um programa de verdade e conhece as empresas que distribuem o Java.
- O que são a JVM, o JRE e o JDK, e como um fica dentro do outro.
- Quais ferramentas vêm no JDK (
javac,java,jshell,javap…). - O que tem dentro de um arquivo
.class: o bytecode, visto comjavap -c. - O que é uma "distribuição" do OpenJDK e como escolher uma (Temurin, Oracle, Corretto, Microsoft, Liberica, Zulu).
- Por que aparece
javac: comando não encontradomesmo com o Java instalado.
Os exemplos acontecem na máquina fictícia da Ana, que tem o Temurin JDK 25 instalado na pasta /opt/jdk-25 (a aula Instalar no Linux mostra como).
A ideia: um estúdio de música
Pense em música gravada num disco de vinil:
- O disco é o seu programa compilado, o arquivo
.class. Ele sozinho não toca nada. - O toca-discos é a JVM: a máquina que lê o disco e faz o som sair.
- O aparelho de som completo (toca-discos, amplificador, caixas de som) é o JRE: tudo o que você precisa para ouvir música.
- O estúdio de gravação é o JDK: tem um aparelho de som completo para ouvir e as ferramentas para gravar discos novos.
Quem só quer ouvir música compra um aparelho de som. Quem quer gravar precisa do estúdio. Você vai criar programas, então precisa do JDK.
┌──────────────────────── JDK (Java Development Kit) ────────────────────────┐ │ ferramentas de desenvolvimento: javac, jshell, javap, jar, javadoc, jdb… │ │ │ │ ┌──────────────────── JRE (Java Runtime Environment) ──────────────────┐ │ │ │ biblioteca padrão: String, Math, listas, datas, arquivos, rede… │ │ │ │ │ │ │ │ ┌──────────────────── JVM (Java Virtual Machine) ────────────────┐ │ │ │ │ │ executa o bytecode: interpretador, compilador JIT, memória │ │ │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────────────────────────────────────────────────┘
| Sigla | Nome em inglês | Tradução | O que faz | Quem precisa |
|---|---|---|---|---|
| JVM | Java Virtual Machine | Máquina Virtual Java | Executa o bytecode dos arquivos .class. Gerencia a memória e faz a compilação JIT. | Todo mundo que roda Java (ela vem dentro do JRE e do JDK). |
| JRE | Java Runtime Environment | Ambiente de Execução Java | A JVM mais a biblioteca padrão e o comando java. Roda programas prontos. | Quem só usa programas Java. |
| JDK | Java Development Kit | Kit de Desenvolvimento Java | Tudo do JRE mais as ferramentas de desenvolvimento, começando pelo compilador javac. | Quem escreve programas Java. Você. |
A palavra runtime quer dizer "hora de rodar", e kit é um conjunto de ferramentas. Repare na ordem: JVM ⊂ JRE ⊂ JDK. Instalando o JDK, você tem as três.
Abrindo o JDK
O JDK é só uma pasta com arquivos. Na máquina da Ana, ela fica em /opt/jdk-25. Veja o que tem dentro:
$ ls /opt/jdk-25 bin conf include legal lib man NOTICE release
| Pasta ou arquivo | O que guarda |
|---|---|
bin | Os programas que você roda no terminal: java, javac, jshell… (bin vem de binaries, "binários", programas executáveis). |
lib | A biblioteca padrão e a própria JVM (bibliotecas, de library). É a maior parte do JDK. |
conf | Arquivos de configuração (segurança, rede). |
include | Arquivos para quem liga Java a código em C. Você não vai usar. |
legal, NOTICE | Licenças. |
man | Os manuais (man javac, em inglês). |
release | Um arquivo de texto com a versão exata e quem fez esta distribuição. |
A pasta bin é a caixa de ferramentas. Repare que java e javac estão lá, lado a lado:
$ ls /opt/jdk-25/bin jar javap jdeps jlink jps jstatd jarsigner jcmd jfr jmap jrunscript jwebserver java jconsole jhsdb jmod jshell keytool javac jdb jimage jnativescan jstack rmiregistry javadoc jdeprscan jinfo jpackage jstat serialver
São 30 programas, mas um iniciante usa poucos. Os que aparecem neste guia:
| Ferramenta | Para que serve | Aula |
|---|---|---|
javac | O compilador: transforma .java em .class (de Java compiler). | javac e java |
java | O lançador: liga a JVM e executa um programa. | javac e java |
jshell | Um console para testar código linha por linha. | JShell |
javap | Mostra o que tem dentro de um .class (de Java printer, ou "desmontador"). | esta aula |
jar | Junta vários .class num arquivo só, o .jar. | Empacotar em JAR |
javadoc | Gera páginas de documentação a partir dos comentários /** */. | Javadoc |
jdb | O depurador de linha de comando. | Depurar |
jlink, jpackage | Montam um Java sob medida para um programa e criam instaladores. | Módulos |
O arquivo release diz exatamente qual Java é este. As primeiras linhas:
$ head -5 /opt/jdk-25/release IMPLEMENTOR="Eclipse Adoptium" IMPLEMENTOR_VERSION="Temurin-25.0.4.1+1" JAVA_RUNTIME_VERSION="25.0.4.1+1-LTS" JAVA_VERSION="25.0.4.1" JAVA_VERSION_DATE="2026-08-18"
IMPLEMENTOR ("quem implementou") é a organização que montou este JDK: a Eclipse Adoptium, que distribui o Temurin. JAVA_VERSION é a versão: 25, com a quarta atualização de segurança (os números são explicados em Versões e LTS).
E o JRE, onde está?
Até o Java 8, a Oracle distribuía o JRE separado, e era isso que as pessoas instalavam para "ter Java" no computador. A partir do Java 11, a Oracle e o OpenJDK pararam de publicar um JRE separado: a ideia é que cada programa traga o seu Java (o jlink monta um sob medida). Ainda assim, algumas distribuições e os sistemas Linux continuam oferecendo um pacote "só para rodar". No Ubuntu, o pacote openjdk-25-jre instala um Java assim. Compare a pasta bin dele com a do JDK:
$ ls /usr/lib/jvm/java-25-openjdk-amd64/bin java jpackage keytool rmiregistry « só 4 programas: nada de javac nem jshell
Tem o java, que roda programas, mas falta o javac. Quem instala só esse pacote consegue rodar um .class pronto e não consegue compilar. É o problema da seção Quando dá errado.
Bytecode: o que tem dentro de um .class
Na aula anterior você viu que o javac traduz o código para bytecode, a linguagem da JVM. Vamos ver esse bytecode de verdade. A Ana escreveu um programa pequeno, que soma dois números:
public class Soma {
public static void main(String[] args) {
int a = 2;
int b = 3;
System.out.println(a + b);
}
}
As linhas novas: int a = 2; cria uma caixinha chamada a, para números inteiros, com o valor 2 (você vai estudar isso em Variáveis). A última linha escreve a soma das duas. Compilando e rodando:
$ javac Soma.java $ ls -l total 8 -rw-rw-r-- 1 ana ana 392 out 16 18:19 Soma.class « 392 bytes de bytecode -rw-rw-r-- 1 ana ana 146 out 16 18:19 Soma.java « 146 bytes de código-fonte $ java Soma 5
O Soma.class não é texto: se você abrir num editor, verá símbolos estranhos. Quem lê esse arquivo é a JVM. Para nós, humanos, o JDK traz o javap, que traduz o .class de volta para algo legível. Sem opções, ele mostra só o "índice" da classe:
$ javap Soma
Compiled from "Soma.java" « compilado a partir de Soma.java
public class Soma {
public Soma(); « um construtor que o javac criou sozinho
public static void main(java.lang.String[]); « o seu método main
}
Com a opção -c (de code), ele mostra as instruções de bytecode de cada método:
$ javap -c Soma
Compiled from "Soma.java"
public class Soma {
public Soma();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_2
1: istore_1
2: iconst_3
3: istore_2
4: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
7: iload_1
8: iload_2
9: iadd
10: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
13: return
}
Assusta à primeira vista, mas o main é só uma receita de 10 passos, um por linha. A JVM é uma máquina de pilha: ela empilha valores, como pratos, e cada instrução pega os pratos de cima. O número à esquerda é a posição da instrução no arquivo. Leia de cima para baixo:
| Instrução | O que faz | Linha do Java |
|---|---|---|
iconst_2 | Empilha o número inteiro 2 (i de int, const de constante). | int a = 2; |
istore_1 | Tira o 2 da pilha e guarda na variável número 1 (a a). | |
iconst_3 | Empilha o 3. | int b = 3; |
istore_2 | Guarda o 3 na variável número 2 (a b). | |
getstatic #7 | Empilha o System.out, a saída padrão. | System.out.println(a + b); |
iload_1 | Empilha o valor da variável 1 (o 2). | |
iload_2 | Empilha o valor da variável 2 (o 3). | |
iadd | Tira os dois números de cima, soma e empilha o resultado: 5 (add = somar). | |
invokevirtual #13 | Chama o println do System.out com o 5 (invoke = chamar). O (I)V quer dizer "recebe um int, devolve nada". | |
return | Termina o método. | a chave } |
Por que a variável a é a número 1, e não 0? Porque a posição 0 é ocupada pelo args, o parâmetro do main (você vai conhecê-lo em Argumentos da Linha de Comando). E o construtor Soma(), que você não escreveu, é criado automaticamente pelo javac em toda classe sem construtor (veja Construtores).
Programadores Java quase nunca leem bytecode. O objetivo aqui é só tirar o mistério: o .class é uma lista de instruções simples para a JVM, gerada a partir do seu código. Instruções como iadd são iguais em qualquer sistema; é a JVM de cada computador que as transforma em instruções do processador.
A assinatura do arquivo: CAFEBABE
Todo arquivo .class começa com os mesmos quatro bytes, escritos em hexadecimal (base 16): CA FE BA BE. É o "número mágico" que identifica um .class, uma brincadeira dos criadores do Java com cafe babe. O comando xxd mostra os bytes de um arquivo:
$ xxd Soma.class | head -1 00000000: cafe babe 0000 0045 001b 0a00 0200 0307 .......E........ $ javap -v Soma | grep major major version: 69 « 0x45 em hexadecimal = 69 = Java 25
Logo depois do cafe babe vem a versão do formato: 0045 em hexadecimal é 69, que quer dizer Java 25. Cada versão do Java tem o seu número (Java 21 = 65, Java 17 = 61, Java 8 = 52: é sempre a versão mais 44). Uma JVM mais antiga recusa um .class de versão mais nova; você vai ver esse erro em javac e java.
Missão: em vez de somar, faça o programa multiplicar a por b e mostrar 6. Em Java, a multiplicação usa o asterisco *. No bytecode, o iadd viraria imul.
public class Soma {
public static void main(String[] args) {
int a = 2;
int b = 3;
System.out.println(a + b);
}
}
public class Soma {
public static void main(String[] args) {
int a = 2;
int b = 3;
System.out.println(a * b);
}
}
Distribuições: muitos JDKs, um só Java
O código do Java é desenvolvido no projeto aberto OpenJDK. Mas o OpenJDK publica principalmente o código; alguém precisa compilá-lo, testá-lo, empacotá-lo para cada sistema e publicar as atualizações de segurança. Cada organização que faz isso oferece uma distribuição (uma "versão de fábrica") do JDK. É como o mesmo refrigerante engarrafado por fábricas diferentes: o sabor é o mesmo, mudam o rótulo e quem dá a garantia.
Todas as distribuições abaixo passam pelos mesmos testes de compatibilidade (o TCK, a "prova oficial" do Java). Um programa que roda numa roda nas outras, e todas as saídas deste guia seriam iguais em qualquer uma delas, mudando só as linhas do java -version.
| Distribuição | De quem | Licença e preço | Atualizações e suporte |
|---|---|---|---|
| Eclipse Temurin | Fundação Eclipse (projeto Adoptium), com apoio de várias empresas | Livre (GPL com exceção de classpath), grátis para qualquer uso | Atualizações das versões LTS por anos; suporte pago oferecido por empresas parceiras. É a usada neste guia. |
| Oracle JDK | Oracle | Licença própria da Oracle: grátis, inclusive em produção, para a versão LTS mais recente, até um ano depois da LTS seguinte; depois, as atualizações exigem assinatura paga | Suporte pago (assinatura Java SE). Confira os termos atuais no site da Oracle antes de usar numa empresa. |
| Oracle OpenJDK (jdk.java.net) | Oracle | Livre (GPL com exceção de classpath), grátis | Só recebe atualizações por 6 meses, até a versão seguinte sair. Bom para testar novidades. |
| Amazon Corretto | Amazon | Livre, grátis | Atualizações das LTS por muitos anos; é o Java usado na nuvem da Amazon (AWS). |
| Microsoft Build of OpenJDK | Microsoft | Livre, grátis | Só versões LTS (11, 17, 21, 25); usado no Azure. |
| BellSoft Liberica | BellSoft | Livre, grátis | Tem uma versão "Full" que já inclui o JavaFX (interfaces gráficas); suporte pago opcional. |
| Azul Zulu | Azul Systems | Livre, grátis | Versões para muitos sistemas e processadores, inclusive antigos; suporte pago opcional. |
| Pacotes do Linux | Debian, Ubuntu, Fedora, Red Hat, Arch… | Livre, grátis | Atualizados pelo próprio sistema, junto com o resto (veja Instalar no Linux). |
Qual escolher?
| Situação | Sugestão |
|---|---|
| Você está aprendendo (este guia) | Temurin 25, ou o pacote openjdk-25-jdk do seu Linux. Os dois são gratuitos e iguais em comportamento. |
| Você usa Linux e quer atualizações automáticas | O pacote do próprio sistema. |
| A empresa roda na nuvem da Amazon ou da Microsoft | Corretto ou Microsoft Build of OpenJDK, que essas nuvens já usam. |
| A empresa exige um contrato de suporte | Oracle JDK com assinatura, ou o suporte pago de Azul, BellSoft, Red Hat ou parceiros do Adoptium. |
| Você quer experimentar a versão mais nova (não LTS) | Oracle OpenJDK em jdk.java.net, ou Temurin da versão mais recente. |
Cada distribuição se identifica no java -version. Compare a do Temurin, usada no guia, com a do pacote do Ubuntu, ambas da mesma versão 25.0.4.1:
$ java -version openjdk version "25.0.4.1" 2026-08-18 LTS OpenJDK Runtime Environment Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS) « Temurin OpenJDK 64-Bit Server VM Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS, mixed mode, sharing) $ /usr/lib/jvm/java-25-openjdk-amd64/bin/java -version openjdk version "25.0.4.1" 2026-08-18 OpenJDK Runtime Environment (build 25.0.4.1+1-1-26.04.4-Ubuntu) « pacote do Ubuntu OpenJDK 64-Bit Server VM (build 25.0.4.1+1-1-26.04.4-Ubuntu, mixed mode, sharing)
Mesma versão, mesmo comportamento; muda só o "rótulo" de quem montou.
Quando dá errado
javac: comando não encontrado, mas o java funciona
$ java -version openjdk version "25.0.4.1" 2026-08-18 OpenJDK Runtime Environment (build 25.0.4.1+1-1-26.04.4-Ubuntu) OpenJDK 64-Bit Server VM (build 25.0.4.1+1-1-26.04.4-Ubuntu, mixed mode, sharing) $ javac -version bash: javac: comando não encontrado $ echo $? 127
O que aconteceu: o computador tem um Java para rodar programas (um JRE, como o pacote openjdk-25-jre do Ubuntu), mas não o JDK. O java existe; o javac, não. O código 127 é o jeito do terminal dizer "comando não existe". É muito comum em computadores onde o Java veio instalado por causa de algum outro programa.
Como resolver: instale o JDK (no Ubuntu, sudo apt install openjdk-25-jdk; ou o Temurin). Os passos estão em Instalar no Linux e Instalar no Windows e macOS. O mesmo vale para jshell: comando não encontrado e javap: comando não encontrado.
.class no editor e só vejo símbolos estranhos
O que aconteceu: o .class é bytecode, não texto. Editores de texto mostram os bytes como letras aleatórias. Não edite um .class: mude o .java e compile de novo.
Como ver o conteúdo: javap -c NomeDaClasse, como nesta aula.
.java e fiquei só com o .class
O que aconteceu: o programa ainda roda (java Soma), mas o código-fonte se foi, e o javap -c mostra bytecode, não o seu código. Sempre guarde os arquivos .java: eles são o seu trabalho; o .class é só o resultado da compilação e pode ser gerado de novo a qualquer momento.
Referência
| Termo | Em uma frase |
|---|---|
| JVM | A máquina virtual que executa bytecode. |
| JRE | JVM + biblioteca padrão + comando java: para rodar. |
| JDK | JRE + javac, jshell, javap, jar…: para criar. |
| Bytecode | As instruções da JVM, guardadas nos arquivos .class. |
javap NomeDaClasse | Lista os métodos de uma classe compilada. |
javap -c NomeDaClasse | Mostra o bytecode de cada método. |
| OpenJDK | O projeto aberto onde o Java é desenvolvido. |
| Distribuição | Um JDK montado e mantido por uma organização (Temurin, Corretto, Oracle…). |
Brinque com o código: troque os valores de a e b, experimente subtração (-) e divisão (/). Tente a / b com a = 7 e b = 2: o resultado vai surpreender (a explicação está em Operadores Aritméticos).
public class Soma {
public static void main(String[] args) {
int a = 7;
int b = 2;
System.out.println(a - b);
System.out.println(a / b);
}
}
Exercícios
1. Qual destas peças você precisa instalar para escrever e compilar programas Java?
2. O comando java -version funciona, mas javac -version diz "comando não encontrado". O que está instalado?
3. No javap -c, qual instrução faz a soma de dois inteiros?
4. Por que existem várias distribuições do JDK (Temurin, Corretto, Zulu…)?
5. A assinatura do .class
Complete com os quatro bytes (em hexadecimal, sem espaço) que começam todo arquivo .class:
Resumo
- JVM executa bytecode; JRE = JVM + biblioteca (para rodar); JDK = JRE + ferramentas (para criar). Você precisa do JDK.
- O JDK é uma pasta; os programas ficam em
bin(javac,java,jshell,javap…). - O
.classcontém bytecode: instruções simples comoiconst_2,iadd,invokevirtual. Ojavap -cmostra. - Todo
.classcomeça comCAFEBABEe traz a versão do formato (69 = Java 25). - O OpenJDK é o projeto aberto; Temurin, Oracle, Corretto, Microsoft, Liberica e Zulu são distribuições, quase todas gratuitas.
javac: comando não encontradocom ojavafuncionando = só o JRE instalado. Instale o JDK.