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.

Você vai aprender
  • 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 com javap -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 encontrado mesmo 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    │  │  │
│  │  └────────────────────────────────────────────────────────────────┘  │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────────┘
SiglaNome em inglêsTraduçãoO que fazQuem precisa
JVMJava Virtual MachineMáquina Virtual JavaExecuta 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).
JREJava Runtime EnvironmentAmbiente de Execução JavaA JVM mais a biblioteca padrão e o comando java. Roda programas prontos.Quem só usa programas Java.
JDKJava Development KitKit de Desenvolvimento JavaTudo 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 arquivoO que guarda
binOs programas que você roda no terminal: java, javac, jshell… (bin vem de binaries, "binários", programas executáveis).
libA biblioteca padrão e a própria JVM (bibliotecas, de library). É a maior parte do JDK.
confArquivos de configuração (segurança, rede).
includeArquivos para quem liga Java a código em C. Você não vai usar.
legal, NOTICELicenças.
manOs manuais (man javac, em inglês).
releaseUm 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:

FerramentaPara que serveAula
javacO compilador: transforma .java em .class (de Java compiler).javac e java
javaO lançador: liga a JVM e executa um programa.javac e java
jshellUm console para testar código linha por linha.JShell
javapMostra o que tem dentro de um .class (de Java printer, ou "desmontador").esta aula
jarJunta vários .class num arquivo só, o .jar.Empacotar em JAR
javadocGera páginas de documentação a partir dos comentários /** */.Javadoc
jdbO depurador de linha de comando.Depurar
jlink, jpackageMontam 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çãoO que fazLinha do Java
iconst_2Empilha o número inteiro 2 (i de int, const de constante).int a = 2;
istore_1Tira o 2 da pilha e guarda na variável número 1 (a a).
iconst_3Empilha o 3.int b = 3;
istore_2Guarda o 3 na variável número 2 (a b).
getstatic #7Empilha o System.out, a saída padrão.System.out.println(a + b);
iload_1Empilha o valor da variável 1 (o 2).
iload_2Empilha o valor da variável 2 (o 3).
iaddTira os dois números de cima, soma e empilha o resultado: 5 (add = somar).
invokevirtual #13Chama o println do System.out com o 5 (invoke = chamar). O (I)V quer dizer "recebe um int, devolve nada".
returnTermina 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).

Você não precisa saber bytecode

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çãoDe quemLicença e preçoAtualizações e suporte
Eclipse TemurinFundação Eclipse (projeto Adoptium), com apoio de várias empresasLivre (GPL com exceção de classpath), grátis para qualquer usoAtualizações das versões LTS por anos; suporte pago oferecido por empresas parceiras. É a usada neste guia.
Oracle JDKOracleLicenç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 pagaSuporte pago (assinatura Java SE). Confira os termos atuais no site da Oracle antes de usar numa empresa.
Oracle OpenJDK (jdk.java.net)OracleLivre (GPL com exceção de classpath), grátisSó recebe atualizações por 6 meses, até a versão seguinte sair. Bom para testar novidades.
Amazon CorrettoAmazonLivre, grátisAtualizações das LTS por muitos anos; é o Java usado na nuvem da Amazon (AWS).
Microsoft Build of OpenJDKMicrosoftLivre, grátisSó versões LTS (11, 17, 21, 25); usado no Azure.
BellSoft LibericaBellSoftLivre, grátisTem uma versão "Full" que já inclui o JavaFX (interfaces gráficas); suporte pago opcional.
Azul ZuluAzul SystemsLivre, grátisVersões para muitos sistemas e processadores, inclusive antigos; suporte pago opcional.
Pacotes do LinuxDebian, Ubuntu, Fedora, Red Hat, Arch…Livre, grátisAtualizados pelo próprio sistema, junto com o resto (veja Instalar no Linux).

Qual escolher?

SituaçãoSugestã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áticasO pacote do próprio sistema.
A empresa roda na nuvem da Amazon ou da MicrosoftCorretto ou Microsoft Build of OpenJDK, que essas nuvens já usam.
A empresa exige um contrato de suporteOracle 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.

Abri o .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.

Apaguei o .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

TermoEm uma frase
JVMA máquina virtual que executa bytecode.
JREJVM + biblioteca padrão + comando java: para rodar.
JDKJRE + javac, jshell, javap, jar…: para criar.
BytecodeAs instruções da JVM, guardadas nos arquivos .class.
javap NomeDaClasseLista os métodos de uma classe compilada.
javap -c NomeDaClasseMostra o bytecode de cada método.
OpenJDKO projeto aberto onde o Java é desenvolvido.
DistribuiçãoUm 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 .class contém bytecode: instruções simples como iconst_2, iadd, invokevirtual. O javap -c mostra.
  • Todo .class começa com CAFEBABE e 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 encontrado com o java funcionando = só o JRE instalado. Instale o JDK.