[picture]

Pacotes

Programação 3: Orientação a Objetos e Java


Uma classe pode ser vista como um tipo especial de módulo. De fato, classes agrupam vários tipos de definições: métodos, atributos, inicializadores, etc. Em particular, uma classe é um tipo de módulo que oferece mecanismos para esconder declarações, através do uso do qualificador private, por exemplo. No entanto, classes têm uma função bem específica: definir tipos.

Por outro lado, conforme discutido anteriormente, sabemos que diferentes tipos de módulos têm funções diferentes; isto é, módulos podem ser usados de várias maneiras, com propósitos específicos. Em especial, para descrever sistemas de grande porte é importante dispor, além de classes, de um tipo de módulo que sirva para agrupar classes relacionadas. Assim torna-se mais fácil localizar uma determinada classe entre as centenas ou milhares de classes que normalmente fazem parte de um sistema de grande porte.

O agrupamento de classes oferece um nível a mais de abstração em relação à abstração apresentada por uma classe isolada. O nome de um grupo de classes pode ser usado para facilitar a localização de uma de suas classes; isto é, para localizar uma classe podemos apenas saber o agrupamento ao qual ela pertence e então localizar a mesma dentro deste agrupamento, o que é muito mais fácil de ser feito já que sempre haverá muito menos agrupamentos do que classes. Por exemplo, a biblioteca básica de Java inclui vários pacotes, cada um contendo classes fortemente relacionadas: java.io (contém classes para realizar entrada/saída de dados), java.awt (contém classes para definir interfaces gráficas), java.net (contém classes de suporte a utilização de Internet/WWW), etc.

Para agrupar a definição de classes relacionadas, Java suporta a noção de pacotes. Como vimos anteriormente, um pacote é também um tipo especial de módulo. Com classes e pacotes, Java fornece recursos linguísticos essenciais para a modularização de sistemas, permitindo que a estrutura do sistema reflita a estrutura de uma visão particular da realidade, o que pode ser muito importante para facilitar tanto a reusabilidade quanto a estensibilidade de software.

Pacotes e Diretórios

Tipicamente um pacote em Java contém as declarações de várias classes relacionadas. Essas classes são armazenadas em várias unidades de compilação (arquivos do sistema operacional). Cada uma destas unidades de compilação deve ter no início a seguinte declaração:
  package pacote;
onde pacote é o nome do pacote ao qual a unidade pertence. Além disso, todas esta unidades devem estar localizadas no mesmo diretório do sistema operacional.

Note então a forte ligação entre o conceito de diretório e o conceito de pacote em Java; em resumo, cada pacote é representado por um diretório contendo vários arquivos com o mesmo cabeçário, indicando o nome do pacote, onde cada arquivo define uma ou mais classes que fazem parte do pacote.

Além disso, na implementação atual de Java, o nome de um pacote deve ser parte do nome do seu diretório associado. Usando o sistema UNIX como exemplo, podemos definir um pacote chamado aulas.aula11.banco contendos dois arquivos que estão no diretório

   /home/java/public_html/graduacao/aulas/aula11/banco
assumindo que o compilador Java foi informado para procurar pacotes embaixo do diretório
   /home/java/public_html/graduacao
Os monitores poderão informar como fazer isso nos ambientes diponíveis para usar Java.

Apesar de um pacote corresponder a um diretório, o conceito de subdiretório não implica no conceito de subpacote; isto é, se um diretório contém subdiretórios, estes não correspondem a subpacotes. De fato, o conceito de subpacote não existe em Java. Por exemplo, um pacote chamado aulas.aula11.bancos.contas não tem necessariamente nenhuma relação direta com o pacote aulas.aula11.bancos, apesar dos arquivos do primeiro estarem num subdiretório do diretório onde estão os arquivos do segundo. O fato de que o primeiro pacote é referenciado no segundo é apenas um acaso do exemplo.

Ocultando Informações

Pacotes são especialmente úteis para ocultar informações. Com este intuito, Java permite que as definições de métodos, atributos, inicializadores e classes sejam acompanhadas de qualificadores especiais: Por exemplo, veja como usar os qualificadores acima:
  public class Banco {
    private Conta[]       contas;
    ...
    public void cadastro(Conta c) {...} 
    ...
    protected Conta procura(long num) {...}
    ...
    public Banco () {...}
  }

Importação de Pacotes

As declarações feitas em uma unidade de compilação são visíveis em qualquer outra unidade do mesmo pacote, a menos que elas sejam declaradas privadas, como veremos mais adiante.

Além disso, qualquer unidade de compilação de um pacote pode usar definições de outros pacotes, desde que elas sejam visíveis. Assim, se em uma unidade de compilação do pacote segundo.pacote for preciso usar o tipo (classe ou interface, juntamente com todas operaçoes e atributos visíveis) Tipo definido no pacote primeiro.pacote temos que fazer as seguinte declarações:

package segundo.pacote;
...
import primeiro.pacote.Tipo;
...
o que permite que o nome Tipo seja usado como sinônimo para
primeiro.pacote.Tipo
dentro da unidade de compilação contendo as declarações acima. Dessa forma note que o pacote segundo.pacote não poderá ter a definição de um tipo com o nome Tipo.

Alternativamente, pode-se usar as declarações

package segundo.pacote;
...
import primeiro.pacote.*;
...
para importar todos os tipos públicos declarados no pacote primeiro.pacote.

É importante notar que importação de pacotes não é transitiva nem distribui sobre as unidades de compilação de um pacote. Por exemplo, considere a seguinte unidade de compilação

package terceiro.pacote;
...
import segundo.pacote.*;
...
Se nesta unidade for preciso utilizar o tipo Tipo definido no pacote primeiro.pacote, temos que adicionar a seguinte declaração
...
import primeiro.pacote.Tipo;
...
à unidade, mesmo que primeiro.pacote.Tipo tenha sido importado por segundo.pacote.

Além disso, se na unidade de compilação

package terceiro.pacote;
...
precisa-se usar alguma definição do pacote segundo.pacote temos que incluir a seguinte declaração
...
import segundo.pacote.*;
...
mesmo que esta declaração já tenha sido incluída em outra unidade de compilação do pacote terceiro.pacote.

Nomeando Pacotes e Unidades de Compilação

Cada unidade de compilação só pode definir um tipo público. De fato, para a implementação atual de Java, as unidades de compilação devem ser nomeadas de acordo com o seguinte padrão: NomedoTipoPúblico.java.

Para facilitar a identificação universal de pacotes que podem ser usados remotamente, estes devem ser nomeados usando-se o endereço Internet de onde o pacote está localizado. Por exemplo, BR.di.ufpe.segundo.pacote deveria ser usado ao invés de simplesmente segundo.pacote.


Paulo Borba (phmb@di.ufpe.br)