Informações

Tipo: Tutorial
Data de Publicação: 01/01/2004
Revisado em: 01/01/2004

Vote!

  • Currently 4,4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags Relacionadas

introducao certificacao

Comentários ( 4 )

Imprimir

Modificadores da Linguagem java

por:

Fernando Ney (fernando_ney@yahoo.com.br)

Neste capítulo explicaremos o uso dos modificadores em Java, tais palavras-chave são usadas sobre as partes de uma classe, ou seja, atributos, métodos, construtores e sobre a própria classe, de agora em diante, por motivos didáticos, chamaremos essas partes de membros da classe. Os modificadores Java são: public, protected, private, static, abstract, final, native, synchronized, transient e volatile.

Introdução

Alguns modificadores podem ser classificados como pertencentes a um grupo chamado modificadores de acesso, tais modificadores (public, protected, private) ditam como membros de uma classe são visíveis por outras classes. Os outros modificadores não possuem uma organização clara e serão explicados um a um.

Para cada modificador será explicado o resultado de aplicá-lo sobre cada um dos seguintes elementos da linguagem: variáveis, métodos, construtores e classes (classes internas serão explicadas no módulo 6 desse tutorial de certificação).

Dúvidas podem ser tiradas pelo endereço fernando_ney@yahoo.com.br

Modificadores de Acesso

Como dito antes modificadores de acesso controlam como membros de uma classe são visíveis por outras classes e instâncias de outras classes.

Um membro de uma classe pode ter um ou nenhum modificador de acesso na sua declaração, quando não especificamos um dos três modificadores de acesso dizemos que o membro tem acesso friendly.

  • private
  • O modificador de acesso private e o mais restritivo de todos, variáveis, métodos e construtores com esse modificador são visíveis somente dentro da definição da própria classe, acessando-o diretamente ou através de uma instância da mesma classe.

    O modificador private pode ser usado em variáveis, métodos e construtores. Em classes, seu uso é restrito a classes internas, ou seja, classes declaradas dentro de outras classes (veremos classes internas no módulo 6).

    Considere os códigos das Figuras 01 e 02:

     1. public class Pilha {
     2.	
     3.     private int topo, capacidade, dados[];
     4.	
     5.     public Pilha() {
     6.		topo = -1;
     7.		capacidade = 10;
     8.		dados = new int[capacidade];
     9.	    }
    10.	
    11.	    public void empilhar(int i) {
    12.		if ( topo+1==capacidade ) 
    13.		    realocar(capacidade*2);	
    14.		dados[++topo] = i;
    15.	    }
    16.	
    17.	    public int desempilhar() {
    18.		return dados[topo--];
    19.	    }
    20.	
    21.	    public void unir(Pilha p) {
    22.		realocar(capacidade + p.capacidade);
    23.		for (int i=0; i<=p.topo; i++)
    24.		    dados[i+p.topo+1] = p.dados[i];
    25.		topo += p.topo + 1;	
    26.	    }
    27.	
    28.	    private void realocar(int novaCapacidade) {
    29.		capacidade = novaCapacidade;
    30.		int temp[] = new int[capacidade];
    31.		for (int i=0; i<=topo; i++)
    32.		    temp[i] = dados[i];
    33.		dados = temp;
    34.	    }
    35.	}
    
    Figura 1: Código da Classe Pilha.java
    1.	public class TestarPilha {
    2.	    public static void main(String args[]) {
    3.		Pilha p1 = new Pilha();
    4.		Pilha p2 = new Pilha();
    5.	
    6.		for (int i=0; i<10; i++) {
    7.		    p1.empilhar(i);
    8.		    p2.empilhar(i+10);
    9.		}
    10.		p1.unir(p2);
    11.		p1.realocar();            	 
    		//erro de compilacao (acesso privado)
    12.		System.out.println(p2.topo); 
    		//erro de compilacao (acesso privado)
    13.	    }
    14.	}
    
    Figura 2: Código da Classe TestarPilha.java

    Na linha 22 do código 01 vemos o acesso a uma variável privada através de uma instância da classe Pilha (p.capacidade), esse acesso é permitido já que quando declaramos que uma variável é privada estamos dizendo que essa variável é visível dentro da definição da própria classe, acessada diretamente ou por intermédio de instâncias da mesma classe. Declarações semelhantes são usadas nas linhas 23, 24 e 25.

    Nas linhas 11 e 12 do código 02, tentamos acessar o método privado realocar() e o atributo topo também privado, isso gera um erro de compilação, pois os elementos privados de uma classe podem somente ser acessados dentro da própria classe. Veja, por exemplo, o acesso aos mesmos elementos realocar() e topo no código 01 nas linhas 13 e 14 respectivamente, esses acessos não causam erros de compilação pois estão dentro da definição da classe Pilha na qual esses elementos são declarados.

    Imagine agora se incluirmos na classe Pilha o método main da classe TestarPilha, conforme podemos ver na Figura 03:

    1.	public class Pilha {
    	  
    //linhas 2 a 35 idem ao código 01
    
    36.	    public static void main(String args[]) {
    37.		Pilha p1 = new Pilha();
    38.		Pilha p2 = new Pilha();
    39.	
    40.		for (int i=0; i<10; i++) {
    41.		    p1.empilhar(i);
    42.		    p2.empilhar(i+10);
    43.		}
    44.		p1.unir(p2);
    45.		p1.realocar();		   		 
    		//Nao ha erro de compilacao, estamos dentro da classe Pilha
    46.		System.out.println(p2.topo); 
    		//Nao ha erro de compilacao, estamos dentro da classe Pilha
    47.	    }
    48.	}
    
    Figura 3: Outra versão para a Classe Pilha.java

    O programa compilará corretamente, pois o método realocar() e a variável topo estão sendo acessadas internamente a classe Pilha (lembre-se que o método main é um método da classe Pilha) diferente do exemplo anterior, onde era acessada da classe TestarPilha.

    Uma relação curiosa ocorre quando herdamos de uma classe que contêm elementos privados, veja da Figura 04, que herda da classe Pilha:

     1.	public class SubPilha extends Pilha {
     2.	    public Pilha(int t, int c) {
     3.		topo = t;	//erro de compilacao
     4.		capacidade = c;	//erro de compilacao
     5.	    }
     6.	}
    
    Figura 4: Código da Classe SubPilha.java

    Apesar da classe SubPilha conter os atributos topo e capacidade herdados de Pilha, o acesso a essas variáveis nas linhas 3 e 4 não é permitido já que foram declarados privados na classe Pilha.

  • "friendly"
  • O acesso friendly em Java decorre da não especificação de nenhum dos três modificadores de acesso (private, protected, public), na verdade não há nenhuma palavra chave que defina que um determinado elemento terá acesso friendly. O acesso friendly pode ser aplicado a classes, métodos, variáveis e construtores. Outros nomes também usados para designar esse tipo de acesso são: "package" e "default".

    O efeito de aplicarmos o acesso friendly a um elemento (ou seja, não aplicar nenhum dos três modificadores) e que elementos com esse tipo de acesso podem somente ser acessados por classes do mesmo pacote.

    1.	class Friendly {
    2.	   int variavelFriendly;
    3.	
    4.	   void metodoFriendly () {
    5.	       System.out.println(variavelFriendly);
    6.	   }
    7.	}
    
    Figura 5: Código da Classe Friendly.java

    No código da Figura 05 podemos ver a definição de uma classe, um método e uma variável com acesso friendly, todos esses elementos são acessíveis de qualquer classe do mesmo pacote, ou seja, qualquer classe que está no mesmo diretório.

    É importante lembrar que a não especificação do pacote de uma classe resulta na incorporação dessa classe ao pacote default, portanto, todas as classes onde não é especificado o seu pacote e que contêm elementos com o acesso friendly, tais elementos são visíveis por todas as outras classes que também não foram especificados pacotes, e isso em grande parte das vezes não é o que desejamos.

  • protected
  • O modificador de acesso protected define que variáveis, métodos e construtores com esse modificador podem somente ser acessados por classes no mesmo pacote ou subclasses da classe onde o elemento foi definido, é importante notar que para os elementos serem acessados na subclasse não é preciso estar no mesmo pacote da classe pai. O modificador protected pode ser aplicado somente em variáveis, métodos e construtores, o seu uso em classes não é permitido.

    Considere os códigos da Figuras 06, 07 e 08:

    1.	package banco;
    2.	
    3.	public class Conta {
    4.	
    5.	    public Conta() { }
    6.	
    7.	    protected float saldo;
    8.	
    9.	    protected void saque(float s) {
    10.	        saldo -= s;
    11.	    }
    12.	}
    
    Figura 06: Código da Classe Conta.java
    1.	public class Poupanca extends banco.Conta {
    2.	    public void reajuste(float juros) {
    3.	        saldo *= juros;
    4.	    }
    5.	}
    
    Figura 07: Código da Classe Poupanca.java
    1.	package banco;
    2.	
    3.	public class Transferencia {
    4.	    public void transferir(Conta c1, Conta c2, float valor) {
    5.	        c1.saque(valor);
    6.		  c2.saldo += valor;
    7.	    }
    8.	}
    
    Figura 08: Código da Classe Poupanca.java

    Como a variável saldo é declarada protected (linha 7 do código 06) o acesso a essa variável na linha 3 do código 07 não causa erro, pois a classe Poupanca é uma subclasse de Conta. Nas linhas 5 e 6 do código 08 podemos ver a outra forma de acesso de membros declarados protected, apesar da classe Transferencia não ser subclasse de Conta, esta pode acessar elementos declarados protected, pois pertence ao mesmo pacote de Conta.

    Caso eliminássemos a linha 1 do código 08 o compilador apresentaria um erro informando que não foi possível determinar a variável saldo e o método saque.

  • public
  • O mais abrangente de todos os tipos de acesso, o modificador public declara que elementos com esse modificador são acessíveis de qualquer classe Java. Este modificador é aplicável a variáveis, métodos, construtores e classes.

    Falaremos agora sobre os demais modificadores Java, começaremos falando que nenhum desses modificadores podem ser usados com construtores, isso significa que modificadores de construtores são apenas os modificadores de acesso citados até aqui.

    Outros Modificadores

  • final
  • O modificador final pode ser aplicado a variáveis, métodos e classes. O comportamento descrito pelo operador final varia de elemento para elemento, mas tem um conceito em comum, o conceito de imutabilidade, isto é, elementos final não podem ser mudados.

    No caso de uma classe, quando dizemos que está é final, dizemos que ela não pode ser herdada, considere a definição da classe Imutavel no código 10.

    1. public final class Imutavel {}
    
    Figura 10: Código da Classe Imutavel.java

    Qualquer tentativa de herança a partir da classe Imutavel irá causar um erro de compilação, como exemplo tente compilar o código 11.

    1. public class Impossivel extends Imutavel {}	//erro de compilacao
    
    Figura 11: Código da Classe Impossível.java

    O erro informado pelo compilador é o seguinte: "cannot inherit from final Imutavel".

    Há pelo menos dois bons motivos para se declarar classes final, segurança e design. Em relação à segurança você pode querer declarar sua classe final de modo que uma subclasse não possa ser substituída dentro de um sistema, onde essa nova classe poderá ter códigos indesejáveis a seu sistema. Um exemplo de classe final é a classe String, essa classe é vital para a normal operação da Máquina Virtual Java, já que todos os programas Java precisam dela, pois ela é declarada como parâmetro no método main(String args[]).

    O outro motivo é simplesmente uma questão de design, por exemplo, você pode desejar declarar classes que implementam seus algoritmos como classes final.

    Métodos final não podem ser redefinidos, ou seja, caso você herde de uma classe que contenha métodos com esse modificador, esses métodos não podem ser redefinidos na sua subclasse. Os mesmos objetivos que motivam o uso do modificador final em classes também motivam seu uso em métodos.

    1.	public class Transacao {
    2.	    public final boolean verificarSenha() {
    3.	        ...
    4.	    }
    5.	}
    
    Figura 12: Código da Classe Transacao.java
    1.	public class TransacaoPublica extends Transacao {
    2.	    public final boolean verificarSenha() {  //erro de compilacao
    3.	       ...
    4.	    }
    5.	}
    
    Figura 13: Código da Classe TransacaoPublica.java

    Na linha 2 do código 13 tentamos redefinir o método verificarSenha(), o compilador proíbe a redefinição e apresenta o seguinte erro: "verificarSenha() in TransacaoPublica cannot override verificarSenha() in Transacao; overridden method is final".

    O último elemento à que o modificador final pode ser aplicado é a atributos. Atributos final não podem ter seus valores mudados, ou seja, são constantes, a partir do momento que se define o seu valor inicial, esse será o seu valor durante todo o ciclo de vida do objeto.

    Quando trabalhamos com objetos devemos notar que apenas o valor do objeto, ou seja, sua referência, não pode ser mudada, atributos não final de uma instância podem ser mudados conforme podemos ver no código 14.

     1.	public class Carro {
     2.	   public final int numeroDeRodas = 4;
     3.	   public int numeroDePortas = 4;
     4.	
     5.	   public static void main(String args[]) {
     6.	       Carro c1, c2;
     7.	       final Carro c3;
     8.	      
     9.	       c1 = new Carro();
    10.	       c1.numeroDeRodas = 5;  //erro de compilacao
    11.	
    12.	       c2 = c3 = c1;
    13.	       c2.numeroDePortas = 2;
    14.	       c3.numeroDePortas = 2;
    15.	
    16.	       c3 = c2;  //erro de compilacao
    17.	   }
    18.	}
    
    Figura 14: Código da Classe Carro.java

    Na linha 10 tentamos atribuir o valor 5 a variável numeroDeRodas, essa atribuição causa um erro de compilação já que estamos tentando mudar o valor de uma variável final. Na linha 12, atribuímos a c3 a referência para c1, essa atribuição é correta já que é a primeira vez que atribuímos um valor a essa variável, já na linha 16 tentamos novamente mudar o seu valor, o que resulta em um erro de compilação. Na linha 14 mudamos o valor de um atributo de um objeto declarado como final, isso é correto já que não estamos mudando o valor do objeto (sua referência), mas sim o valor de um atributo que não é final.

  • abstract
  • O modificador abstract pode ser aplicado somente a classes e métodos. Classes abstratas provem um modo de adiar a implementação de métodos para subclasses. Uma classe abstrata não pode ser instanciada, ou seja, não podemos chamar seus construtores.

    Veja como exemplo o código 16. A classe Figura pode ser herdada para criar classes tais como, Retangulo, Triangulo, Quadrado, Circulo, entre outros, nesse caso a classe Figura teria atributos comuns entre esses objetos, mas você não poderia aplicar o operador new a classe Figura, ou seja, não poderia criar uma instância dessa classe.

    1.	public abstract class Figura {
    2.	    public abstract void desenhar();
    3.	
    4.	    public static void main(String args[]) {
    5.	        Figura f;
    6.	        f = new Figura();  //erro de compilacao
    7.	    }
    8.	}
    
    Figura 16: Código da Classe Carro.java

    Na linha 5 declaramos um objeto do tipo Figura, o qual não causa erro já que a restrição em relação a classes abstratas é que estas não podem ser instanciadas com vemos na linha 6, mas podem sim, ser declaradas.

    Métodos abstratos são métodos os quais você em um determinado nível de programação ainda não sabe como implementá-los, mas sabe que eles serão necessários, veja, por exemplo, o método desenhar() na classe Figura. No momento de design da classe não é possível ainda conhecer como desenhar instâncias desses objetos, mas se saberá no momento que criamos uma subclasse, como por exemplo, para definir uma classe Circulo, nesta classe você já tem todas as informações necessárias para implementação desse método.

    Classes devem ser declaradas abstratas quando qualquer uma das três afirmativas abaixo forem verdadeiras:

    a) a classe contêm métodos abstratos;

    b) a classe herda de classes abstratas e não define todos os seus métodos abstratos;

    c) a classe implementa uma interface, mas não declara todos os seus métodos.

    Note que essas são condições em que a classe obrigatoriamente deve ser declarada como abstrata, mas uma classe pode não cair em nenhum das três afirmativas acima e ainda ser declarada como abstrata.

    De uma forma geral uma classe deve ser declarada abstrata quando sua definição está incompleta.

  • static
  • Este modificador pode ser aplicado a variáveis, métodos e a uma porção de código que não está dentro de nenhum método, geralmente referenciado como bloco estático.

    A idéia geral sobre o modificador static é que elementos com esse modificador estão associados com a classe e não com instâncias dessa classe.

    Uma variável estática é compartilhada por todas as instâncias de uma classe, ou seja, ao invés de cada instância da classe ter uma cópia dessa variável ela é uma única variável compartilhada por todos as instâncias. Para a existência de uma variável estática não é preciso nem mesmo a criação de uma instância da classe que contenha a variável, é necessário somente que a classe seja carregada na Máquina Virtual Java, já que está é criada e inicializada no momento de carga da classe.

    Em relação a métodos as mesmas explicações são verdadeiras, ou seja, métodos podem ser chamados mesmo sem nenhuma instância da classe ter sido construída. Um bom exemplo de métodos estáticos existe em toda aplicação Java, o método main() é invocado sem a existência de nenhuma instância.

    Métodos e variáveis podem ser referenciados além da forma padrão (através do nome do objeto) através do nome da classe. Embora as duas formas sejam corretas e trabalham exatamente da mesma forma a primeira pode tornar-se confusa quando referenciando métodos e variáveis estáticas, levando o programador a pensar que este método ou variável é não estático. Por esse motivo e conveniente sempre referenciar variáveis estáticas através do nome da classe para evitar confusões.

    É importante dizer que métodos estáticos podem somente acessar variáveis também estáticas, ou seja, é proibido o uso de variáveis não estáticas dentro de blocos estáticos, com exceção de variáveis criadas dentro do próprio bloco é claro. Essa restrição se deve ao fato de que é possível fazer uma chamada a um método estático mesmo sem haver nenhuma instância dessa classe, ou seja, a provável variável a ser referenciada dentro do método pode nem mesmo ter sido criada ainda. Outro motivo dessa restrição é caso haja várias instâncias criadas, qual é a instância que contêm a variável na qual estamos referenciando?.

    Outra importante característica é que não podemos usar a palavra chave this com métodos e variáveis estáticas, já que este é uma referência para o objeto que contém o método o qual não é verdadeiro para métodos e variáveis estáticas já que estes não pertencem a um objeto em particular, mas sim a classe.

    Um outro local onde podemos usar o modificador static são nos desconhecidos blocos de código estáticos de Java. Veja o código da Figura 19.

    1.	public class BlocoEstatico {
    2.	  static int i = 4;
    3.	  
    4.	  static {
    5.	    System.out.println("Carregando BlocoEstatico\r\n valor de i: " + i);
    6.	  }
    7.	
    8.	  public static void main(String args[]) {
    9.	    System.out.println("metodo main");
    10.	  }
    11.	}
    
    Figura 19: Código da Classe Carro.java

  • native
  • Algumas vezes é necessário executar código não Java em aplicações. Quando desejamos acessar chamadas do Sistema Operacional, interfacear com dispositivos de hardware, reusar código não Java, implementar código onde o tempo é um parâmetro critico, etc. Esse modificador é usado somente em métodos e sua definição está fora da Maquina Virtual Java, em bibliotecas C e C++.

    A declaração de um método nativo é bastante semelhante a declaração de métodos em interfaces, não existe a definição do método. A chamada a esses métodos é exatamente da mesma forma que métodos não nativos.

  • transient
  • É aplicado somente a variáveis. Quando uma variável é declarada transient ela não é guardada como parte do estado de persistência do objeto.

    Muitas vezes é necessário escrever dados para fora da Máquina Virtual Java, quando isso ocorre nenhum dos mecanismos de segurança da linguagem é válido e se existe informações que não devem ser escritas as variáveis que contem esses dados devem ser declaradas como modificador transient para que estes não sejam escritos para fora da Máquina Virtual Java.

  • synchronized
  • Esse modificador é usado para sincronizar o acesso a código em ambientes paralelos. Este modificador será coberto no capitulo 07 onde veremos threads e métodos de sincronização.

  • volatile
  • São aplicados somente a variáveis. Este modificador indica que variáveis podem ser modificadas assincronamente e o compilador não deve fazer qualquer assunção sobre ela. O modificador volatile ainda não está em comum uso e não é citado como assunto do exame de certificação.

    Comentários (4)

    É muito bom ter acesso a um site que ofereça conhecimento na área de informática abrangendo um conteúdo de fácil compreensão, além de gratuito.
    postado por Rafael Allan Almeida Batalha Rodrigues em 30/07/2007 às 23:21
    Otimo conteudo.. Mto bem explicado. Obrigado pelo material. Abraço!
    postado por Marcos Felipe em 31/07/2007 às 23:21
    Material excelente! Foi muito útil pra mim. Em matéria de modificadores de acesso, esse é um dos melhores que já li e testei.
    postado por Davey Silveira Balbino em 24/06/2008 às 23:21
    tenho um trabalho de facu que envolve essas classes principalmente a de carro,mas tambem preciso fazer uma de moto e outra de caminhonete,se alguem puder me dar uma força. grato desde jah.
    postado por VITOR em 30/08/2008 às 23:21
    Comente!

    Observações

    Os campos em negrito são obrigatórios.

    Para evitar problemas, este espaço é moderado. Após o envio do comentário será necessário aguardar pela sua aprovação.