[OCPJP6] 016 – Orientação a objetos

Sobrecarga de construtores

Como vimos anteriormente o grande propósito de um construtor é instanciar uma classe, e indo além podemos definir contratos para instanciar uma determinada classe, ou seja, definir atributos obrigatórios e/ou padrões.

Por exemplo, uma classe Quadrado(int lado) define que toda instância de Quadrado obrigatoriamente deve atribuir um valor “lado”.

Legal né… E se eu quisesse oferecer a possibilidade de instanciar um Quadrado com lados fracionários? Quadrado(double lado)

package certificacao;
public class Quadrado {
    double lado;
    public Quadrado(int l) { this.lado = l; }
    public Quadrado(double l) { this.lado = l; }
}

E se houvesse uma herança (generalização -> especialização)? Até onde poderiamos ir? 😛

  • O construtor mais específico irá ser chamado
  • Se houver ambiguidade não irá compilar
package certificacao;
public class Pessoa {
    public Pessoa() { System.out.println("()"); }
    public Pessoa(Object param1) { System.out.println("(Object)"); }
    // Lembre-se: String é uma especialização de Object
    public Pessoa(String param1) { System.out.println("(String)"); }
}

– E se eu fizesse: new Pessoa(null); o que aconteceria?

Se você respondeu: (String) você acertou, porque String é a classe mais específica entre Object e String 😉

 – E seu ao invés de Pessoa(Object param1) eu tivesse Pessoa(Integer param1) o que aconteceria?

new Pessoa(null); não compilaria, porque o compilador não saberia o que fazer, já que Integer e String são ambíguos a null. Para funcionar seria necessário um cast new Pessoa((String)null);. Veremos mais sobre cast em breve.

Comentem, estendam o assunto… Compartilhem =)

[OCPJP6] 015 – Orientação a objetos

Construtores

Os construtores tem um grande propósito em orientação a objetos, criar uma instância de uma classe 🙂

Refresque-se [008], Complemente…

Regras

  • Um construtor pode ter vários argumentos.
  • Uma classe pode ter mais de um construtor.
  • Em herança:
    • Se a classe base (generalização) tiver apenas um construtor com argumentos, as classes especializadas devem implementar um construtor com os mesmos argumentos (podendo ser subtipos).
    • Todo construtor de uma especialização chama primeiro o construtor base super() implicitamente se não declarado.
    • Não pode declarar/implementar nada acima de uma chamada super().
    • Diferente dos métodos, diminuir ou aumentar o nível de acesso é possível.

Exemplos

1. Argumentos

package certificacao;
public class Animal {
    public Animal(Number n1) { System.out.println("animal"); }
}
package certificacao;
public class Cachorro extends Animal { }

A classe Cachorro não irá compilar porque é obrigatório a declaração do construtor com argumentos da classe base Animal.

public Cachorro (Number n1) { // ...

2. Argumentos

package certificacao;
public class Cachorro extends Animal {
    public Cachorro () { }
}

Mesma situação do exemplo 1 e mais 🙂

O que mais? Por um motivo oculto. Todo construtor chama implicitamente primeiro o construtor base super() e neste caso a classe base Animal não tem um construtor sem argumentos.

3. Argumentos

package certificacao;
public class Cachorro extends Animal {
    public Cachorro (Integer i1) { System.out.println("cachorro"); }
}

Também não funciona 😦 Por quê?

Porque o construtor sem argumentos não foi declarado na classe base Animal, e todo construtor irá chamar o método super() implicitamente quando não declarado, e nesse caso não irá encontrar também. Para funcionar…

package certificacao;
public class Cachorro extends Animal {
    public Cachorro (Integer i1) {
        super(i1);
        System.out.println("cachorro");
    }
}

🙂

Comentem, estendam o assunto… Compartilhem =)

[OCPJP6] 014 – Orientação a objetos

Iniciando com sobrecarga

Diferentemente da sobrescrita, na sobrecarga o compilador olha para a referência da variável e não a sua instância. Como assim? Referência ou instância?

No post [009] comentei sobre variáveis primitivas e de referência e deixei para descrever um pouco mais sobre herança e polimorfismo mais pra frente, e no post [012] o assunto polimorfismo apareceu como uma das coisas mais belas na orientação a objetos e agora vamos entender o que é referência e instância antes de começar com sobrecarga 🙂

// Lembra disso?
SerVivo cachorro = new Cachorro();

No exemplo acima SerVivo é a referência e Cachorro é a instância da variável.

Agora que estamos entendidos o que você acha que acontecerá no código abaixo?

package certificacao;
public class MainSobrecarga {
    public static void main(String[] args) {
        MainSobrecarga ei = new MainSobrecarga();
        Homem duvida = new Menino();
        ei.mostraMinha(duvida);
    }
    public void mostraMinha(Homem h) {
        System.out.println("homem"); }
    public void mostraMinha(Menino m) {
        System.out.println("menino"); }
}

homem ou menino?

homem é a resposta correta! O compilador vai interpretar a referência da variável e utilizar o método mostraMinha(Homem) 🙂

Mais e mais…

  • Sobrecarga de construtores (em breve)
  • E mais… Para o próximo tema “Atribuições”

Comentem, estendam o assunto… Compartilhem =)

[OCPJP6] 013 – Orientação a objetos

Sobrescrita

Dando continuidade ao assunto herança (generalização e especialização), a sobrescrita é uma forma de especializar um método, alterando o comportamento da classe base (geral). Algumas regras:

  • O tipo de retorno deve ser o mesmo ou um subtipo.
  • O nível de acesso NÃO pode ser mais restritivo. (public > protected)
  • O nível de acesso pode ser menos restritivo. (protected > public)
  • Pode sobrescrever pra uma exceção de subtipo.
  • A declaração pode ser exatamente igual.

Vamos ver em exemplo:

package certificacao;
public abstract class SerVivo {
    public abstract String locomover();
}
package certificacao;
public abstract class Humano extends SerVivo {
    public String locomover() { return "caminhando"; }
    public String dormir() { return "Dorme 8h dia"; }
    // Controle de acesso default
    abstract String tirarCartaMotorista();
}

Aumentando o nível de acesso de default para protected.

package certificacao;
public class Homem extends Humano {
    // AUMENTAR o controle de acesso para protected.
    // private não compilaria
    protected String tirarCartaMotorista() {
        return "Depois dos 18 anos."; }
    protected String seAlistarTiroDeGuerra()
        throws AlistamentoException { return "Alistado!"; }

    class AlistamentoException extends Exception { }
    class ForaDeIdadeException extends AlistamentoException { }
}

Diminui o subtipo de exceção para uma classe especializada de AlistamentoException

package certificacao;
public class Menino extends Homem {
    // SIMPLES: Altera o comportamento do método
    public String dormir() {
        if (idadeEntreSeisQuinzeAnos()) {
            return "Dorme 12h dia";
        }
        return super.dormir();
    }
    // DIMINUI o Subtipo da exceção
    // Se fosse ao contrario não compilaria
    protected String seAlistarTiroDeGuerra()
        throws ForaDeIdadeException {
        throw new ForaDeIdadeException(); }
}

Comentem, estendam o assunto… Compartilhem =)

[OCPJP6] 012 – Orientação a objetos

Polimorfismo

Para iniciar a sessão de orientação a objetos, uma das coisas mais belas na orientação a objetos, o polimorfismo.

É importante termos conhecimento do que é herança em orientação a objetos. Resumidamente herança é a forma de compartilhar atributos e métodos de uma classe base (generalização) para suas classes derivadas (especializações).

O polimorfismo é uma forma de “assinar” algo de modo geral (generalização), ou seja, sem se preocupar com as especialidades de cada especialização. Confuso? Vamos ver em código 🙂

Em um exemplo simples… tudo começa assim…

-Object
    '- SerVivo
        '- Animal
            '- Cachorro
            '- Lagarto
        '- Humano
            '- Homem
            '- Mulher

SerVivo é a classe base (generalização) e os demais são as derivadas (especializações).

package certificacao;
public abstract class SerVivo {
    public abstract String locomover();
}
package certificacao;
public abstract class Animal extends SerVivo { }
package certificacao;
public class Cachorro extends Animal {
    @Override
    public String locomover() { return "pulando"; }
}
package certificacao;
public class Lagarto extends Animal {
    @Override
    public String locomover() { return "se arrastando"; }
}
package certificacao;
public abstract class Humano extends SerVivo {
    @Override
    public String locomover() { return "caminhando"; }
}
package certificacao;
public class Homem extends Humano { }
package certificacao;
public class Mulher extends Humano { }

Executando

package certificacao;
import java.util.ArrayList;
import java.util.List;

public class PolimorfismoMain {
    public static void main(String[] args) {
        List<SerVivo> seresVivos = criaSeresVivos();
        // POLIMORFISMO: Para este código,
        // Não importa o que o método locomover faz em cada especialização
        // =D
        for (SerVivo serVivo : seresVivos) {
            System.out.println(serVivo.getClass().getName()
                + " | " + serVivo.locomover());
        }
    }
    public static List<SerVivo> criaSeresVivos() {
        List<SerVivo> seresVivos = new ArrayList<SerVivo>();
        // cachorro
        SerVivo cachorro = new Cachorro();
        seresVivos.add(cachorro);
        // lagarto
        SerVivo lagarto = new Lagarto();
        seresVivos.add(lagarto);
        // mulher
        SerVivo mulher = new Mulher();
        seresVivos.add(mulher);
        // homem
        SerVivo homem = new Homem();
        seresVivos.add(homem);
        return seresVivos;
    }
}

Console

certificacao.Cachorro | pulando
certificacao.Lagarto | se arrastando
certificacao.Mulher | caminhando
certificacao.Homem | caminhando

Em código, você deve pensar que não precisa se preocupar como o homem ou o cachorro vão se locomover, deixe que a especialização faça seu papel em execução =). O polimorfismo simplifica a implementação de uma funcionalidade de execução (Serviço) 😉

Em breve outras características de herança em Java: sobrescrita e sobrecarga.

Comentem, estendam o assunto… Compartilhem =)

[OCPJP6] 011 – Declarações e controle de acesso

Finalizando declarações e controle de acesso

transient

O modificador transient só pode ser aplicado a variáveis. Ao marcar uma variável como transient indicamos a máquina virtual do Java que ignore-a na serialização. (Serialização significa gravar um objeto e seu estado em um tipo de stream, exemplificando, é possível salvar um objeto em um arquivo. Comenterai mais pra frente sobre serialização.)

// ...
private transient int posicaoX;

volatile

Basicamente volatile é usada para indicar que o valor da variável poderá ser modificada por diferentes threads. Tudo que precisamos saber para a certificação sobre este modificador é de que só pode ser aplicado a variáveis.

static “conceitos básicos”

Onde é possível usar?

  • métodos
  • variáveis
  • inner class
  • blocos de inicialização
public class CalculadoraUtil {

    // variaveis
    public static Integer UM = 1;
    public static Integer DOIS;

    // blocos de inicializacao
    static {
        DOIS = 2;
    }

    // metodos
    public static Double soma(Double... numeros) {
        Double result = Double.valueOf(0);
        for (Double d : numeros) {
            result = result + d;
        }
        return result;
    }

    // inner class
    static class Formula { }
}

Mais pra frente irei dedicar um post só para static =D

Comentem, estendam o assunto… Compartilhem =)

[OCPJP6] 010 – Declarações e controle de acesso

Declaração de enums

Acreditem, enum muito mais que um conjunto fixo de valores pré-determinados 🙂

Posso dizer que é uma das minhas partes preferidas na linguagem Java. Antes do Java 1.5 utilizava-se muito constantes (static final) para pré-determinar valores, com a vinda do enum, além de deixar mais claro um valor pré-determinado muitas outras coisas legais vieram juntos.

Você sabia?

  • Em tempo de execução cada valor/constante se torna uma classe estática, sendo assim pode definir atributos, ter um construtor.
  • E mais, um enum pode implementar métodos.
  • E mais, um enum pode implementar uma interface.
  • E muito mais: sobrecarca, sobrescrita =D

Vamos ver algumas técnicas na prática

Simples

package certificacao;
public enum Situacao {
ABERTO, EM_PROCESSAMENTO, FINALIZADO, CANCELADO
}

Poderoso

package certificacao;
public interface Medida {
double getQuantidade();
}
package certificacao;
public enum TamanhoCopo implements Medida {
GRANDE(600),

MEDIO(350) {
// SOBRESCRITA de método
@Override
public boolean isReciclavel() { return false; }
},

PEQUENO("Mini Plastic");

// Atributos
private double ml = 200;
private String marca = "Generic Plastic";

// Construtores
private TamanhoCopo(double m) { this.ml = m; }
// SOBRECARGA de construtor
private TamanhoCopo(String m) { this.marca = m; }

// Métodos
public boolean isReciclavel() { return true; }
public String getMarca() { return marca; }
// Implementação de método
@Override
public double getQuantidade() { return ml; }

}

Comentem, estendam o assunto… Compartilhem =)