Grupo de Usuários Java http://www.guj.com.br Conceitos de Programação Orientada a Objetos Tatyana Bitencourt Com as técnicas de orientação a objeto, é possível obter resultados considerados impossíveis pensando de maneira estruturada. Como Java não deixa ao programador a opção de escrever ou não orientado a objetos (como em C++), os conceitos de oop devem estar bem fundamentados. Abstração A capacidade de determinar o problema de maneira geral, dando importância apenas aos seus aspectos relevantes e ignorando os detalhes é chamada de abstração. Existem dois tipos de abstração: Abstração de dados e Abstração de Procedimentos. - Abstração de dados Abstração de dados é a definição de um tipo de dado por seu comportamento e estado, utilizandose métodos. A manipulação desse dado é realizada apenas através de seus métodos. Um exemplo é classificar uma lista a partir das operações aplicadas a ela, como inserção e remoção. Qualquer objeto do tipo lista só pode sofrer modificações através dessas operações. - Abstração de procedimentos Consiste em considerar um procedimento com uma operação bem definida como algo único, mesmo que utilize outros procedimentos internos. Usamos abstração de procedimentos quando uma função divide-se em outras sub-funções, que por sua vez decompõem-se em outras funções. Classe Tipo definido pelo usuário. Contém a especificação da classe, identificando seus atributos (dados) e seus métodos (comportamento da classe). A definição de uma classe não é responsável pela criação de nenhuma instância, portanto não ocupa uma parte da memória. Considere a classe a seguir: public class Person { private String name; public Person(String a) { name = a; //copia a para name } public String getName() { return name; } public String toString() { return "Nome: " + name; } } Grupo de Usuários Java – http://www.guj.com.br – Página 1 Grupo de Usuários Java http://www.guj.com.br A instrução inicial public class Person declara uma classe chamada Person, que possui como um atributo private String name; e três métodos públicos: public Person(String a); public String getName(); public String toString(); Objeto Em uma linguagem procedural, a instância de uma estrutura é chamada de variável. Já uma instância de uma classe é chamada de objeto. A classe informa a cada objeto suas características (dados) e seu comportamento (métodos). Suas características são informadas pela declaração de variáveis de tipo primitivo (int, float, etc...) ou classes anteriormente definidas. Seus métodos são definidos por funções, possibilitando a “conversa” entre dois objetos. - Criando objetos Após a definição da classe Person, a instrução Person x = new Person("Maria"), y = new Person(“Andre”); cria dois objetos da classe definida anteriormente Person, passando a ocupar realmente um espaço na memória. - Funções-Membro Quando um objeto chama um método de sua classe (função-membro), costuma-se dizer que uma mensagem foi enviada. Assim, a instrução x.toString(); envia uma mensagem a x, pedindo que retorne seu conteúdo como String. Encapsulamento Encapsulamento consiste em esconder detalhes (dados) e oferecer uma interface comum aos objetos (métodos). Toda vez que uma alteração deve ser feita em alguma variável de instância, deve ser feita através de um método da classe. Caso alguma modificação ocorra em alguma variável de instância, sabe-se exatamente quais métodos interagiram com a variável, prevenindo alterações acidentais. É permitido ao usuário ver apenas os dados necessários, todo o resto é mantido escondido, através de especificadores de acesso (public, private, protected). A utilização de encapsulamento também favorece a reusabilidade e manutenção do código. Dessa maneira, a instrução System.out.println(“Nome: ”,name); chamada por qualquer outro objeto causará um erro, pois o atributo name não está visível (através do modificador private). Para realizar a impressão da variável name é necessário então chamar um método de x: Grupo de Usuários Java – http://www.guj.com.br – Página 2 Grupo de Usuários Java http://www.guj.com.br System.out.println(x.toString()); Herança Herança é a criação de novas classes, chamadas classes derivadas, a partir de classes já existentes, as classes-base. Alguns dos benefícios da utilização de herança é a reutilização do código da classe base, além da possibilidade de implementação de classes abstratas genéricas. Ao implementar um applet, utiliza-se a seguinte instrução: public class HelloApplet extends JApplet { ...... } A palavra chave extends indica que HelloApplet é uma classe derivada de JApplet. Isso siginifica que a classe HelloApplet herda por exemplo, os métodos init() e start() de JApplet. Num applet, pode-se definir novos atributos e métodos, bem como sobrescrever os métodos herdados de JApplet, como o init(). Uma classe derivada (ou subclasse) pode realizar todas as funções que a classe-base (ou superclasse) realizaria. A subclasse herda todos os métodos public da superclasse, mas não possui acesso a nenhum membro private de sua classe-base. Se isso fosse possível, não haveria motivo algum em realizar o encapsulamento de dados. Além disso, uma subclasse pode acrescentar mais alguns métodos ou atributos àqueles herdados da superclasse, possuindo características particulares em relação à classebase. Especificador de acesso protected Além de public e private, Java permite um terceiro tipo de modificadores de acesso: protected. Métodos e atributos declarados como protected possuem um nível intermediário de proteção. Um membro protected é como um membro private, exceto pelo fato de que ele pode ser acessado pelas classes derivadas de uma superclasse. Cada vez que deseja-se utilizar algum método da superclasse, utiliza-se a palavra-chave super seguida pelo operador ponto (. ). Considere a classe Student: public class Student extends Person { private String grade; // serie cursada private int classes; // aulas que frequenta ... public Student(String n, String g) { super(n); //chamada ao construtor da superclasse grade = g; classes = 0; } public String toString() { return super.toString() + “\nGrade: “ + grade; } } //fim da classe Student Grupo de Usuários Java – http://www.guj.com.br – Página 3 Grupo de Usuários Java http://www.guj.com.br A classe acima ilustra a criação de uma subclasse Student que herda os atributos e métodos de Person. Uma subclasse não herda os construtores de sua superclasse, mas pode invoca-los através do comando super. A chamada a essa função deve ser a primeira instrução no construtor da subclasse, caso contrário ocorrerá erro. Caso a chamada ao construtor base não tivesse sido feita explicitamente em Student(String n, String g), uma chamada ao construtor default (sem argumentos) da classe base seria realizada. Em Java não é permitido o uso de herança múltipla como em C++, o que pode ser contornado com o uso de interfaces. Por que Java não suporta herança múltipla Algumas das características da linguagem Java é ser familiar, simples, segura, robusta, etc. Os projetistas da linguagem fizeram-na parecida com C++ (atingindo o conceito de ser familiar) e decidiram não implementar algumas características que tornavam a linguagem C++ um tanto complexa, como herança múltipla e sobrecarga de operadores. Eles simplesmente verificaram que o trabalho não valia a pena. Para contornar esse fato, foi inspirado na linguagem Objective C que surgiu o conceito de interfaces. Um objeto pode herdar diversos métodos, com a condição de que implemente-os. Fonte: Java World (http://www.javaworld.com/javaqa/2002-07/02-qa-0719multinheritance.html) Classes abstratas Uma classe abstrata é utilizada quando deseja-se fornecer uma interface comum a diversos membros de uma hierarquia de classes. Os métodos declarados na classe abstrata serão implementados em suas subclasses, através de polimorfismo. Considere as seguintes modificações na classe Person: public abstract class Person { private String name; public Person(String a) { name = a; //copia a para name } public String getName() { return name; } public String toString() { return "Nome: " + name; } public abstract String getType(); } Grupo de Usuários Java – http://www.guj.com.br – Página 4 Grupo de Usuários Java http://www.guj.com.br O método getType() retorna o tipo de pessoa (estudante, professor, funcionario, etc). A inclusão do método public abstract String getType(); indica que a classe Person é uma classe abstrata, o que justifica a inclusão da palavra-chave abstract na definição da classe. Nenhum objeto da classe Person poderá ser instanciado agora. Agora a classe Student deve se adequar às mudanças realizadas. Ao extender Person, a subclasse possui também um método abstrato, e caso não o sobrescreva será também uma classe abstrata. A classe Student ficaria mais ou menos assim: public class Student extends Person { private String grade; // serie cursada private int classes; // aulas que frequenta ... public Student(String n, String g) { super(n); //chamada ao construtor da superclasse grade = g; classes = 0; } public String toString() { return super.toString() + “\nGrade: “ + grade; } public String getType() { return “Student”; } } //fim da classe Student Implementando o método getType(), a classe Student é agora uma classe concreta. Diferenças entre classe abstrata e interface As semelhanças entre classe abstrata e interface são muitas. Uma interface é utilizada quando não existe a necessidade das classes derivadas herdarem métodos já implementados. Outra diferença é que interfaces não permitem a declaração de atributos, como as classes abstratas. Polimorfismo Polimorfismo caracteriza a criação de funções com um mesmo nome, mas códigos diferentes, facilitando a extensão de sistemas. Um tipo de polimorfismo é a redefinição de métodos para uma classe derivada. Para que isso aconteça, o método deve possuir o mesmo nome, tipo de retorno e argumentos do método sobrescrito. O acréscimo de um segundo construtor à classe Student, como mostra o exemplo, é um exemplo de sobrecarga de métodos. public class Student extends Person Grupo de Usuários Java – http://www.guj.com.br – Página 5 Grupo de Usuários Java http://www.guj.com.br { private String grade; // serie cursada private int classes; // aulas que frequenta ... public Student(String n, String g) { super(n); //chamada ao construtor da superclasse grade = g; classes = 0; } public Student(String n, String g, int c) { super(n); //chamada ao construtor da superclasse grade = g; classes = f; } . . . } //fim da classe Student Quando ocorre a instanciação dos objetos: Student s1 = s2 = new new Student(“Maria”, “5”), Student (“João”,”8”,5); O objeto s1 utiliza o primeiro construtor, pois os tipos de argumento são os mesmo. Já o objeto s2 utiliza o segundo construtor, por ter além dos dois argumentos do tipo String, um outro do tipo int. Em Java não é possível realizar a sobrecarga de operadores como em C++. Conclusão O fato de Java ser orientado a objetos contribui muito para sua utilização no desenvolvimento de sistemas, cada vez mais complexos. Sendo uma linguagem orientada a objetos, Java pode usufruir do melhor das antigas linguagens também orientadas a objetos, como Smaltalk, Objective C, C++. Além disso, a utilização de técnicas como herança e polimorfismo facilitam ainda mais a extensão do software, uma característica extremamente importante em tempos em que a política de não reinventar a roda é cada vez mais forte. Tatyana Bitencourt ([email protected]) é programadora e estudante de Ciência da Computação (UFMS). Grupo de Usuários Java – http://www.guj.com.br – Página 6