Revista Do Linux
 
  
  
 

OUTRAS SEÇÕES
  Cartas
  Variedades
  Rádio Linux
  Mensagem ao Leitor
  CD do Mês
  Coluna do Augusto
  Dicas e Truques
  Opinião
 

O Geek que sabia Java Parte III

Na terceira parte de nosso curso de Java, abordamos o conceito de hierarquia entre classes. Esta é uma aula essencialmente prática, portanto preste muita atenção ao código fonte e aos blocos de comentário entre ele, que dão dicas do que está sendo feito.

Exemplo de uma Hierarquia de Classes. Compile o exemplo a seguir da seguinte forma:

$ javac Livro.java
$ javac LivroTecnico.java
$ javac LivroInfantil.java
As classes LivroTecnico e LivroInfantil apresentam o método main. Esse método define que uma classe pode ser acessada pela Máquina Virtual Java para iniciar a execução de uma aplicação. Toda a classe que tem declarada esse método pode ser passada como parâmetro para o executável java, tal como a seguir:
$ java LivroTecnico
$ java LivroInfantil
Livro.java
class Livro extends Object
{
        // atributos acessados somente
        // dentro da classe
    private int codigo = 0;

        // atributo acessado dentro da classe
        // e pelas classes
        // que herdam desta classe
    protected String nome = null;

        // acessível por outros objetos diretamente
    public String editora = null;

        // acessível por classes pertencentes
        // a este pacote
    int ano = 0;

    public Livro()
    {
        codigo = 0;
        nome = "default";
        editora = "default";
        ano = 2001;
    }

    public Livro(int codigo, String nome)
    {
        this.codigo = codigo;
        this.nome = nome;
        editora = "default";
        ano = 2001;
    }

    public Livro(String nome, int codigo)
    {
        this.codigo = codigo;
        this.nome = nome;
    }

    public Livro(int codigo, String nome, String editora, int ano)
    {
        this.codigo = codigo;
        this.nome = nome;
        this.editora = editora;
        this.ano = ano;
    }

    public void setCodigo(int codigo)
    {
        this.codigo = codigo;
    }

    public void setNome(String nome)
    {
        this.nome = nome;
    }

    public void setEditora(String editora)
    {
        this.editora = editora;
    }

    public void setAno(int ano)
    {
        this.ano = ano;
    }

    public int getCodigo()
    {
        return codigo;
    }

    public String getNome()
    {
        return nome;
    }

    public String getEditora()
    {
        return editora;
    }

    public int getAno()
    {
        return ano;
    }

    public void imprime()
    {
        System.out.println("Livro => "+codigo+", "+nome+", "+editora+", "+ano);
    }
}

LivroTecnico.java
{
    protected String palavras_chave = null;
    public LivroTecnico()
    {
        // chama o construtor da classe
        // pai (superclasse)sem parâmetros
        super();
        palavras_chave = "sem palavras-chave";
    }

    public LivroTecnico(int codigo, String nome, String editora, int ano, String palavras_chave)
    {
        super(codigo, nome, editora, ano);
        this.palavras_chave = palavras_chave;
    }

    public void testeMensagens()
    {
Comentário: acessar private int código da classe-pai gera erros, pois um atributo private somente é acessível pela própria classe. Mesmo herdando da classe que tem o atributo private, não é possível acessá-lo diretamente. Todo atributo protected é acessível pela própria classe e pelas classes que herdarem da classe que os contém.
System.out.println("valor de protected String nome -> "+nome);

Comentário: acessando public String editora. Quando um atributo ou método é public ele pode ser acessado diretamente por qualquer objeto.

System.out.println("valor de public String editora -> "+editora);

Comentário: acessando int ano. Neste caso não há modificadores, qualquer classe-filha ou pertencente ao mesmo pacote pode acessá-la.

System.out.println("valor de  int ano-> "+ano);

        // acessando protected String palavras_chave

        System.out.println("protected String palavras_chave -> "+palavras_chave);
    }

    public void imprime()
    {
        System.out.println("LivroTecnico");
        System.out.println(nome+", "+editora+", "+ano+", "+palavras_chave);
    }

    public static void main(String args[])
    {
        LivroTecnico lt = new LivroTecnico(1, "Linguagens", "Novatec", 2001, "c, c++, java, orientação a objetos");
        lt.testeMensagens();

        Livro lv = new Livro(5, "O Livro Externo", "A Editora", 1930);
Comentário: acessando de forma externa, ou seja, o envio da mensagem para o objeto não é feito dentro da classe System.out.println("Acessando o atributo private int codigo => "+lv.codigo); Isto não funciona, pois private somente é acessível dentro da classe que declara o atributo.
	System.out.println("Acessando o atributo protected String nome => "+lv.nome);
        System.out.println("Acessando o atributo public editora => "+lv.editora);

        // é acessível pois está no mesmo pacote!

        System.out.println("Acessando atributo  int ano => "+lv.ano);
    }
}
LivroInfantil.java

public class LivroInfantil extends Livro
{
    private String colecao = null;

    public LivroInfantil(int codigo, String nome, String editora, int ano, String colecao)
    {
        super(codigo, nome, editora, ano);
        this.colecao = colecao;
    }

    public void imprime()
    {
        System.out.println("LivroInfantil");
        System.out.println(nome+", "+editora+", "+ano+", "+colecao);
    }

    public static void main (String args[])
    {
        LivroTecnico lt = new LivroTecnico(1, "Tutorial Java", "Sun Microsystems", 1992, "java, orientação a objetos, pacotes");
        LivroInfantil li = new LivroInfantil(2, "Branca de Neve", "Editora Infantil", 1931, "princesa, anões");

        System.out.println("Criando um objeto LivroTecnico e outro LivroInfantil");
        lt.imprime();
        li.imprime();

        // o \n dentro do System.out.println
        // faz pular uma linha
        System.out.println("\n\nFazendo um Cast do Objeto LivroTecnico para Livro");
        Livro lv1 = (Livro) lt;
        lv1.imprime();

        System.out.println("\n\nFazendo um
        //Cast do Objeto LivroInfantil para Livro");
        Livro lv2 = (Livro) li;
        lv2.imprime();

        // System.out.println("\n\nForçando
        // um Cast de LivroInfantil
        // para Livro Tecnico");
        // System.out.println("Este Cast é fora da                     // hierarquia de classes");
        // System.out.println("Portanto não
        // funciona!"); LivroInfantil li1 = new
        // LivroInfantil(1, "livro infantil",
        // "editora de livros", 1998,
        // "coleção infantil");
        // LivroTecnico tc1 = (LivroTecnico) li1;

        System.out.println("\n\nFazendo um cast do Pai para o Filho...");
        try
        {
        LivroTecnico _lt = (LivroTecnico) new Livro(7, "o livro", "a editora", 2001);
            _lt.imprime();
        }
        catch(Exception e)
        {
        System.out.println("Não foi possível fazer o cast...");
        }

Comentário: Este cast de Pai para Filho não funciona, pois o que existe no filho não existe no pai, entretanto o que existe no pai existe no filho. Assim, pode-se converter um filho no pai, mas não o contrário. Isto é possível, pois na herança todo o código do pai foi passado para o filho. Entretanto converter o pai no filho gera erros, pois o pai não contém todo o código do filho.

        }
}

Hierarquia, palavra-chave this e Escopo

No exemplo desta seção são aplicados conceitos de hierarquia de classes, uso da palavra-chave this para acesso aos identificadores membro da classe e apresentados conceitos de escopo de forma prática. Esse exemplo é formado pela superclasse Veiculo, que é genérica, como toda superclasse deve ser. As especializações da superclasse Veiculo são feitas na implementação das subclasses Moto e Carro.

Para compilar o exemplo a seguir proceda da seguinte forma:

$ javac Veiculo.java
$ javac Moto.java
$ javac Carro.java

A classe Moto apresenta o método main que possibilita a execução do aplicativo da seguinte forma:

$ java Moto

No código-fonte desse exemplo apresentado a seguir existem diversas explicações sobre o uso de hierarquia, escopo e da palavra-chave this. Veiculo.java

class Veiculo extends Object
{
        private int ano = 0;
        protected String marca = null;

        public Veiculo()
        {
        // acessando variável ano da classe, pois
        // não há nenhuma variável ano definida
        // no escopo deste método
            ano = 2001;
        }

        public Veiculo(int ano)
        {
        // this é o mesmo que um ponteiro para uma
        // instância do objeto, o ponto (.)

            this.ano = ano;

Comentário: quando tentamos acessar uma variável ano o que ocorre? Se esta variável estiver definida dentro do método no qual se está chamando você estará se referindo à variável ano no escopo do método. Portanto, quando nos referimos a ano dentro deste construtor, estamos falando da variável ano definida dentro deste método, ou seja, aquela variável definida como parâmetro do construtor public Veiculo(int ano). Caso a variável ano do construtor não esteja definida estaremos acessando o atributo ano da classe, como no construtor vazio acima!

        }
        public void setAno(int ano)
        {
        // atribuindo o valor da variável ano para
        // o atributo de classe ano
            this.ano = ano;
        }
        public int getAno()
        {
            return ano;
        }
}
Moto.java
class Moto extends Veiculo
{
    public int cilindradas = 0;

    public Moto()
    {
        super();
        cilindradas = 125;
    }

    public Moto(int cilindradas)
    {
        super();
        this.cilindradas = cilindradas;
    }

    public Moto(int ano, String marca, int cilindradas)
    {
        super(ano);

Comentário: O código abaixo acessa o atributo protected marca definido na classe-pai atribuindo-lhe o valor da variável marca definida neste construtor.

        this.marca = marca;
        this.cilindradas = cilindradas;
    }

    public static void main (String args[])
    {
        Moto x = new Moto();
        System.out.println(x.cilindradas);
    }
}

Carro.java

class Carro extends Veiculo
{
    protected int numero_portas = 0;

    public Carro()
    {
        // chamando o construtor do pai com
        // parâmetro vazio!
        super();
        // atributo marca acessível, pois está
        // definido com protected na classe-pai
        marca = "sem marca";
        numero_portas = 2;
        }

    public Carro(int ano, String marca, int numero_portas)
    {
        // chamando contrutor com parâmetro
        // do ano do veículo
        super(ano);
        // atribuindo o valor da variável marca
        // declarada no construtor para o atributo
        // de classe this.marca
        this.marca = marca;
        // atribuindo variável numero_portas para
        // o atributo this.numero_portas da classe
        this.numero_portas = numero_portas;
    }

    public void setNumeroPortas(int numero_portas)
    {
        this.numero_portas = numero_portas;
    }

    public int getNumeroPortas()
    {
        return numero_portas;
    }
}

Na próxima edição, abordaremos os conceitos relacionados ao desenvolvimento de aplicações orientadas a objetos: Levantamento e análise dos requisitos, estudo de caso do sistema, estudo da hierarquia entre as classes e análise da arquitetura. Até lá!


Rodrigo Fernandes de Mello - mello@virgos.com.br
É um dos autores do livro 'Aprendendo Java 2', publicado pela Novatec Editora


A Revista do Linux é editada pela Conectiva S/A
Todos os Direitos Reservados.

Política de Privacidade
Anuncie na Revista do Linux