Construtores e Instanciação


Não é possível criar um objeto sem invocar um construtor; não é possível criar um objeto invocando apenas o construtor do objeto atual, mas também o de suas superclasses. Construtores são códigos executados quando o new é usado; são blocos de inicialização.

Construtor Básico

Toda classe, incluindo classes abstratas, deve ter um construtor; mas isso não quer dizer que é obrigatório tê-lo explicitamente na classe.
Construtores não têm retorno, seus nomes devem combinar exatamente com o nome da classe, e são usados para inicializar o estado de variáveis de instância.

public class Telefone {
      String numero;
      int tipo;  
      // Construtores não possui retorno
      public Telefone(String num, int tipo) {
            this.numero = num;
            this.tipo = tipo;
      }    
      public static void main(String[] args) {
            /* Erro - Essa classe não possui um
             * construtor sem argumentos */
            Telefone telefone = new Telefone();
           
            Telefone telefone2 = new Telefone("79", 1);
      }
}

Construtor Encadeado

Quando existe uma árvore de herança, os construtores se comportam de maneira encadeada.
Por exemplo: existe uma árvore de herança onde Horse herda de Animal e este herda de Object. Ao instanciar uma variável do tipo Horse acontece o seguinte: o construtor de Horse é chamado; todo construtor invoca o construtor da sua superclasse com uma chamada implícita ao método super() (exceto se o construtor de Horse invoca outro construtor sobrecarregado na mesma classe), ou seja, o construtor de Animal é chamado; por sua vez, Animal chama o construtor de Object; como esta é uma classe do topo, todas as suas variáveis são inicializadas com os valores que foram declaradas; o construtor de Object completa a execução; as variáveis de Animal  recebem seus valores explícitos e seu construtor termina a execução;  as variáveis de Horse são inicializadas recebendo seus valores explícitos e seu construtor finaliza a execução.
Isso quer dizer que os construtores sempre são chamados baixo para cima na árvore de herança, mas são executados de cima para baixo, ou seja, primeiro são executados os construtores das superclasses até chegar à última subclasse.

public class Empresa { 
      String cnpj;
      int cod;   
      public Empresa() {
            //const. Empresa chama o const. Object
            this.cnpj = "00000";
            System.out.println("Const. Empresa");
      }
}

public class Filial extends Empresa {
      int codEmpresa;  
      public Filial() {
            //const. Filial chama o c. sobrecarregado
            /*quando um construtor chama outro
             * construtor, a chamada deve estar sempre
             * na primeira linha*/
            this("1111");
            this.codEmpresa = 1;
            System.out.println("Const. Filial");    
      }    
      public Filial(String cnpj) {
            //const. sobrecarregado chama o c. Empresa
            this.cnpj = cnpj;
            System.out.println("C. Sobrecar. Filial");
      }    
}

public class AppEmpresa {   
      public static void main(String[] args) {
            Filial filial = new Filial();
      }
}

Saída dessa execução: Const. Empresa
C. Sobrecar. Filial
Const. Filial

Regras para Construtores

·         Construtores podem usar qualquer modificador de acesso; um construtor privado significa que somente a classe que o declara pode usá-lo; se outra classe quiser acessar uma classe com construtor private, terá que ser através de um método estático ou uma variável que permita acesso a uma instância criada de dentro da classe;
·         O nome do construtor deve ter o mesmo nome da classe;
·         Construtores não devem ter tipos de retorno;
·         É permitido, mas não aconselhável, ter um método com o mesmo nome da classe; a diferença entre os dois é que o método terá um tipo de retorno;
·         Se um construtor não for declarado na classe explicitamente, um construtor default será automaticamente gerado pelo compilador;
·         O construtor default não tem argumentos;
·         Se já existir qualquer construtor na classe, o construtor default não será gerado;
·         Todo construtor possui, na primeira linha, uma chamada explícita ao método super()  (para o construtor da superclasse, se houver) ou a um construtor sobrecarregado através do método this(); caso não haja uma chamada explícita a um desses métodos, o compilador irá gerar uma chamada ao super();
·         Se um construtor for criado, em oposição a chamar o default, e não for feita uma chamada explícita ao método super() ou ao método this(), o compilador irá inserir dinamicamente uma chamada ao super(), caso haja uma superclasse;
·         Uma chamada ao método super() pode ser sem argumento ou incluir argumentos passados para o construtor superior;
·         Um construtor sem argumento não é necessariamente o default, entretanto, o default é sempre um construtor sem argumentos; o construtor default é provido pelo compilador, não é declarado explicitamente;
·         Não é permitido fazer uma chamada a um método de instância, ou acessar uma variável de instância, antes do método super() ou this()  ser executado;
·         Somente variáveis e métodos estáticos podem ser acessados como parte do código para chamar super() e this(). Ex.: super(A.NAME);
·         Classes abstratas possuem construtores, e eles sempre são chamados quando uma classe concreta é instanciada;
·         Interfaces não possuem construtores, porque não fazem parte da árvore de herança de objetos;
·         A única maneira de um construtor ser invocado é de dentro de outro construtor.


Determinando se um construtor default será criado

Se uma superclasse não possui um construtor default ou um construtor sem argumento, a subclasse não poderá ter um construtor default, ou seja, será obrigatória a declaração de um construtor na subclasse para que este possa chamar explicitamente o método super() passando os devidos argumentos.
O construtor default possui o mesmo modificador de acesso da classe, não possui argumentos e possui chamada para o método super().
Construtores não podem ser herdados, pois não são métodos.
Um construtor pode ser diretamente invocado, somente por outro construtor (utilizando uma chamada a super() ou this() ).

public class Roupa {   
      /* classe Roupa não possui construtor
       * default nem construtor sem arg. */
      Roupa(String nome) {}
}

public class Camisa extends Roupa {
      /* como Roupa não possui const. default ou
       * const. sem argumentos, é obrigatória a
       * implementação de um construtor com
       * argumento na subclasse (Camisa) junto
       * com a chamada explícita ao super() */
      Camisa(String i) {
            super(i);        
      }
}

Construtores sobrecarregados

Sobrecarregar um construtor significa escreve-lo em várias versões, cada uma com uma lista de argumentos diferente. A primeira linha de um construtor deve ser uma chamada (explícita ou implícita) a um dos métodos super() ou this(); caso o construtor chame this(), ele não mais chamará super(), a incumbência passará para o próximo construtor chamado por this(), e assim por diante. Isso significa que um construtor nunca poderá ter a chamada para os dois ao mesmo tempo.

Fonte: SCJP Sun Certifi ed Programmer for Java 6 Study Guide

1 comentários:

Unknown disse...

Gostei muito do texto, deu para relembrar algumas coisas aprendidas na faculdade.

Postar um comentário