Modificadores de visibilidade

Visibilidade

Em Java, utilizamos alguns modificadores que nos permitem “proteger” o acesso a um atributo, método ou até mesmo uma classe, de outras classes. Basicamente Java possui quatro modificadores básicos de acesso: private, protected, default e public.

No vídeo a seguir mostramos passo a passo como funciona os modificadores de visibilidade:

Modificador de acesso: private

private é um modificador de acesso que restringe totalmente o acesso aquele recurso da classe de todas as demais classes, sejam elas do mesmo pacote, de outros pacotes ou até subclasses. Este modificador pode ser aplicado a atributos e métodos.

Exemplo:

package br.visibilidade;

/**
 * Classe utilizada para representar um email que será enviado.
 */
public class Email {
  private String remetente;
  private String destinatario;
  private String assunto;
  private String mensagem;

  public void enviarEmail(String remetente, String destinatario,
      String assunto, String mensagem) {
    this.remetente = remetente;
    this.destinatario = destinatario;
    this.assunto = assunto;
    this.mensagem = mensagem;

    if(this.validarEmail()) {
      this.enviar();
    }
  }

  private boolean validarEmail() {
    boolean ok = false;
    // Código para validar se as informações do email estão corretas.
    return ok;
  }

  private void enviar() {
    // Envia o email.
  }
}

Neste exemplo, temos a classe Email, a partir de outras classes podemos chamar apenas o método enviarEmail(…), os outros métodos e atributos da classe não podem ser usados por outras classes pois tem o modificador private.

package br.visibilidade;

/**
 * Classe utilizada para testar o envio de email.
 */
public class TesteEmail {
  public static void main(String[] args) {
    Email email = new Email();
    email.enviarEmail("rafael@sakurai.com.br",
        "cristiano@almeida.com.br",
        "Aula de POO - Visibilidade",
        "Material da aula de visibilidade já está disponivel.");

    email.remetente = "teste@almeida.com.br"; //ERRO de Compilação.
    email.enviar(); //ERRO de Compilação.
  }
}

Neste exemplo conseguimos criar um objeto a partir da classe Email e enviar o email utilizando o método enviarEmail(…), mas não conseguimos acessar o atributo remetente e o método enviar(), pois são privados e o compilador gera dois erros de compilação:

C:\>javac br/visibilidade/TesteEmail.java
br\visibilidade\TesteEmail.java:14: remetente has private access in br.visibilidade.Email
    email.remetente = "teste@almeida.com.br"; // ERRO de Compilação.
         ˆ
br\visibilidade\TesteEmail.java:15: enviar() has private access in br.visibilidade.Email
    email.enviar(); //ERRO de Compilação.
         ^
2 errors

Modificador de acesso: default (ou package)

default é um modificador um pouco menos restritivo que o private. Este tipo de modificador é aplicado a todas as classes, atributos ou métodos, os quais, não tiveram o seu modificador explicitamente declarado.

Este modificador permite que apenas classes do mesmo pacote tenham acesso as propriedades que possuem este modificador.

Neste exemplo, temos uma classe Pessoa que não declarou o modificador, portanto o modificador é o default.

package br.visibilidade;

/**
 * Classe utilizada para representar uma Pessoa.
 */
class Pessoa {
  String nome;
}

Se criarmos outra classe dentro do mesmo pacote br.visibilidade da classe Pessoa, então está classe tem acesso à classe Pessoa também.

package br.visibilidade;

/**
 * Classe utilizada para testar a classe Pessoa.
 */
public class TestePessoaPacote {
  public static void main(String[] args) {
    Pessoa pessoa = new Pessoa();
    pessoa.nome = "Rafael Guimarães Sakurai"; //OK
  }
}

Agora se tentarmos utilizar a classe Pessoa, a partir de outro pacote, terá erro de compilação, pois não tem acesso.

package br.visibilidade.outropacote;

/**
 * Classe utilizada para testar a classe Pessoa.
 */
public class TestePessoaPacote2 {
  public static void main(String[] args) {
    Pessoa pessoa = new Pessoa(); //Não encontra a classe Pessoa.
    pessoa.nome = "Cristiano Camilo dos Santos de Almeida";
  }
}

Quando tentamos compilar essa classe, temos a seguinte mensagem do compilador:

C:\>javac br/visibilidade/outropacote/TestePessoaPacote2.java
br\visibilidade\outropacote\TestePessoaPacote2.java:08: cannot find symbol
symbol: class Pessoa
location: class br.visibilidade.outropacote.TestePessoaPacote2
    Pessoa pessoa = new Pessoa();
    ˆ
br\visibilidade\outropacote\TestePessoaPacote2.java:08: cannot find symbol
symbol: class Pessoa
location: class br.visibilidade.outropacote.TestePessoaPacote2
    Pessoa pessoa = new Pessoa();
                        ˆ

Modificador de acesso: protected

protected é um modificador um pouco menos restritivo que o default. Com este tipo modificador, podemos declarar que um atributo ou método é visível apenas para as classes do mesmo pacote ou para as subclasses daquela classe.

Neste exemplo, temos a classe Produto, e está classe tem o atributo nomeProduto e os métodos getNomeProduto() e setNomeProduto() que possuem o modificador protected.

package br.visibilidade;

/**
 * Classe utilizada para representar um Produto.
 */
public class Produto {
  protected String nomeProduto;

  protected void setNomeProduto(String nomeProduto) {
    this.nomeProduto = nomeProduto;
  }

  protected String getNomeProduto() {
    return nomeProduto;
  }
}}

Se criarmos outra classe no pacote br.visibilidade, podemos utilizar os atributos e métodos protected declarados na classe Produto.

package br.visibilidade;

/**
 * Classe utilizada para testar a visibilidade protected
 * do atributo e métodos da classe Produto.
 */
public class TesteProdutoPacote {
  public static void main(String[] args) {
    Produto prodLapis = new Produto();
    prodLapis.nomeProduto = "Lapis";
    System.out.println(prodLapis.getNomeProduto());

    Produto prodCaneta = new Produto();
    prodCaneta.setNomeProduto("Caneta");
    System.out.println(prodCaneta.getNomeProduto());
  }
}

Se criarmos uma classe em um pacote diferente, não conseguiremos utilizar os atributos e métodos da classe Produto, pois não temos acesso ao método.

package br.visibilidade.outropacote;

import br.visibilidade.Produto;

/**
 * Classe utilizada para testar a visibilidade protected
 * do atributo e métodos da classe Produto a partir de outro
 * pacote.
 */
public class TesteProdutoOutroPacote {
  public static void main(String[] args) {
    Produto prodCaneta = new Produto();
    prodCaneta.setNomeProduto("Caneta");
    System.out.println(prodCaneta.getNomeProduto());
  }
}

Se a classe que está em outro pacote for uma subclasse da classe Produto, então está classe recebe através da herança os atributos e métodos protected. (Veremos o conceito de herança mais adiante.)

package br.visibilidade.outropacote;

import br.visibilidade.Produto;

/**
 * Classe utilizada para representar um Produto.
 */
public class SubProdutoOutroPacote extends Produto {
  public String getProduto() {
    return "Produto: " + getNomeProduto();
  }
}

Modificador de acesso: public

public é o modificador menos restritivo de todos os demais. Declarando classes, atributos ou métodos com este modificador, automaticamente dizemos que aquela propriedade é acessível a partir de qualquer outra classe.

Dentro de um arquivo .java, só pode existir uma classe do tipo public, e está classe precisa obrigatoriamente ter o mesmo nome que o nome do arquivo .java.

Além dos modificadores de acesso, temos vários outros modificadores que serão abordados futuramente. A seguir, temos uma relação de todos os modificadores e os seus respectivos impactos quando aplicados a Classes, Métodos e Atributos.

Modificador Em uma classe Em um método Em um atributo
private Não aplicável Acesso pela classe Acesso pela classe
protected Não aplicável Acesso pelo pacote e subclasses Acesso pelo pacote e subclasses
default Somente pacote Acesso pelo pacote Acesso pelo pacote
public Acesso total Acesso total Acesso total
abstract Não instância Deve ser sobrescrito Não aplicável
final Sem herança Não pode ser sobrescrito Constante
static Não aplicável Acesso pela classe Acesso pela classe
native Não aplicável Indica código nativo Não aplicável
transient Não aplicável Não aplicável Não serializavel
synchonized Não aplicável Sem acesso simultâneo Não aplicável