W3docs

Pacotes Java

Agrupe classes Java relacionadas em pacotes, siga convenções de nomenclatura e estruture projetos para facilitar a manutenção.

Java não tem um único grande pool de nomes de classes. Toda classe vive dentro de um pacote — um espaço nomeado que funciona tanto como unidade de organização quanto como namespace em nível Java. Duas classes chamadas Logger podem coexistir sem conflito, desde que estejam em pacotes diferentes, e o nome do pacote aparece em todo lugar: em declarações import, em nomes totalmente qualificados, no sistema de arquivos e até em manifestos JAR. Conhecer bem os pacotes é o que permite ler a estrutura de um projeto alheio de relance.

Esta página aborda o que é um pacote, como nomeá-lo, o caso especial do pacote padrão, como os nomes de pacotes se mapeiam para diretórios e como declarar um pacote no seu próprio arquivo-fonte.

O que é um pacote, de fato

Um pacote serve a três propósitos ao mesmo tempo:

  • Um namespace. java.util.Date e java.sql.Date são classes diferentes; o nome do pacote as separa.
  • Um limite de acesso. Sem um modificador, os membros são visíveis apenas dentro do mesmo pacote — o nível de acesso "package-private". É uma forma real e estrutural de encapsulamento; veja Modificadores de acesso.
  • Um diretório. O nome do pacote mapeia um-para-um para um caminho de pasta. com.example.app.util fica em com/example/app/util/.

O mesmo nome é usado em três lugares — declaração, caminho de arquivo e import — e todos precisam estar de acordo.

Convenções de nomenclatura

A convenção do Java é a nomenclatura em DNS inverso baseada em um domínio que você controla:

  • Tudo em minúsculas: com.example, não Com.Example.
  • Ordem de domínio invertida: um projeto em w3docs.com usa com.w3docs como raiz.
  • Segmentos de projeto, módulo e funcionalidade seguem: com.w3docs.learnjava.parser.
  • Evite palavras reservadas do Java como segmentos (int, class, new). Se o seu domínio incluir uma delas, modifique-a: com.example.int_ ou divida de forma diferente.

Essas convenções importam além da estética. A regra de DNS inverso é o que torna seguro colocar JARs de diferentes organizações no mesmo classpath sem conflitos de nomes.

O pacote padrão

Um arquivo .java sem declaração package pertence ao pacote padrão (sem nome). Duas coisas acontecem como resultado:

  • Você não pode usar import do pacote padrão em um pacote nomeado. Qualquer coisa nele fica efetivamente isolada do código real.
  • Ferramentas de build, IDEs e sistemas de módulos tratam o pacote padrão como um caso degenerado — muitos simplesmente se recusam a compilar contra ele.

Use-o para arquivos Hello.java isolados. Não distribua nada a partir dele.

Como os pacotes se mapeiam para diretórios

Se você declarar package com.w3docs.learnjava.parser; no topo de Tokenizer.java, o arquivo precisa estar em:

com/w3docs/learnjava/parser/Tokenizer.java

relativo à raiz do código-fonte. O compilador não infere o pacote a partir do caminho — ele lê a declaração e confia em você. Mas o runtime (e a maioria das ferramentas) não ficará satisfeito se os dois não coincidirem.

Essa raiz do código-fonte é onde começa o labirinto do classpath: a JVM precisa saber onde a árvore de pacotes começa, ou não encontrará nada.

Declarando um pacote

A instrução package é o que atribui uma classe a um pacote. Ela deve ser a primeira instrução no arquivo — antes de qualquer import, antes da própria classe. Apenas comentários e linhas em branco podem precedê-la.

// File: com/w3docs/learnjava/parser/Tokenizer.java
package com.w3docs.learnjava.parser;

import java.util.List;

public class Tokenizer {
    public List<String> tokenize(String source) {
        // ...
        return List.of();
    }
}

De qualquer outro lugar, esta classe agora é conhecida pelo seu nome totalmente qualificado, com.w3docs.learnjava.parser.Tokenizer. Código no mesmo pacote pode referenciá-la apenas como Tokenizer; código em outros pacotes precisa importá-la ou escrever o nome completo.

Aviso
Um arquivo pode conter no máximo uma instrução package, e apenas uma classe public de nível superior — cujo nome deve corresponder ao nome do arquivo. Colocar package em qualquer lugar que não seja o topo faz o compilador rejeitar o arquivo.

Um exemplo prático: dois Loggers

O argumento mais claro para pacotes é a colisão que eles previnem. O programa a seguir usa duas classes chamadas Logger em essência — o java.util.logging.Logger do JDK pelo seu nome totalmente qualificado — e mostra como o pacote de uma classe faz parte de sua identidade em tempo de execução.

java— editable, runs on the server

Duas conclusões ao executá-lo: as classes conhecem seu próprio pacote em tempo de execução (via Class.getName() e Class.getPackage()), e o nome totalmente qualificado é o que identifica um tipo de forma inequívoca — Logger sozinho é ambíguo; java.util.logging.Logger não é.

O que vem a seguir

Nomear um pacote é uma coisa; trazer seus tipos para o seu próprio código é outra. O próximo capítulo aborda a instrução import — importações de tipo único, importações com curinga, importações estáticas e quando cada uma é a escolha certa.

Prática

Prática
Por que a convenção padrão do Java para nomes de pacotes usa a ordem de domínio invertida, como `com.example.app`?
Por que a convenção padrão do Java para nomes de pacotes usa a ordem de domínio invertida, como `com.example.app`?
Was this page helpful?