JAVA – Classes e Objectos – Encapsulamento ATAI 1 POO Objectos e Classes Três pilares da POO Encapsulamento Herança Polimorfismo 2 Objecto Objecto identidade atributos Propriedades que definem o estado do objecto (estrutura interna). métodos Identifica o objecto entre a colecção de objectos existentes Acções ou procedimentos que alteram o estado do objecto (comportamento). Objectos podem ser agrupados em Classes 3 Classe Uma CLASSE é um molde que serve de padrão para a criação de Objectos similares designados por instâncias da classe e que caracterizam-se por: Possuem a mesma estrutura interna: atributos Possuem o mesmo interface: métodos CLASSES representam ainda um muito importante mecanismo de partilha de código, dado que os métodos que implementam a funcionalidade de todas as instâncias têm o seu código num único local, ou seja, a sua CLASSE, contendo as instâncias apenas os valores que representam o seu estado interno. 4 Exemplo: Classe Conta class Conta { private final long numeroConta; private double saldo; public Conta (long id) { NumeroConta = id; } public void credito (double valor) { saldo = saldo + valor; } public void debito (double valor) { saldo = saldo - valor; } public double getSaldo () { return saldo; } public long getNumConta () { return numeroConta; } public String toString () { return (“Numero da Conta: ”+ numeroConta + “\tSaldo:” + saldo); } } 5 Classes em UML (Unified Modeling Language) Uma classe é representada por um rectângulo, subdividido em três áreas: A primeira contém o nome da Classe. A segunda contém seus atributos. A terceira contém suas operações. Conta - numeroConta:long - saldo : double + Conta(long) + debito(double) + credito(double) + getSaldo() : double + getNumConta() : long Nome da classe atributos operações 6 Exemplo: Uso da Classe Conta class CriaConta { /** Criar objecto do tipo Conta */ public static void main (String [] args) { Conta conta1, conta2; conta1 = new Conta (4563764); conta2 = new Conta (1238765); conta1.credito(500.00); conta1.debito(45.00); conta2.credito(400.00); conta2.debito(60.00); System.out.println(conta1); System.out.println(conta2); } } 7 Criar Instâncias (Objectos) Em Java, como em qualquer linguagem OO, não é possível definir objectos directamente. É necessário definir primeiro a classe a que o objecto pertence. A classe funciona como um molde que pode ser utilizado para criar qualquer número de objectos semelhantes. A definição de uma classe implica a especificação dos seus atributos (variáveis) e do seu comportamento (métodos). Um objecto é, assim, definido como instância de uma classe e tem todas as variáveis e métodos definidos para essa classe. A operação new cria uma instância de uma classe, e é responsável pela alocação dos objectos em memória. 8 Sobre os Dados Visibilidade dos Dados A visibilidade dos dados é a zona do programa no qual os dados podem ser utilizados. Dados declarados fora dos métodos podem ser usados por todos os métodos da classe. Instanciação dos dados As variáveis numeroConta e saldo na classe Conta são atributos de instancia, porque cada objecto da Classe Conta possui uma variável não partilhada. Numa classe são declarados os atributos, mas não é reservado memória para eles. Dados declarados num método só podem ser usados no método. Sempre que um objecto Conta é criado, novas variáveis numeroConta e saldo são criadas. Todos os objectos partilham o código dos métodos, mas cada um possui o seu espaço de dados. 9 Métodos Especiais: Construtor similares a métodos; possuem o mesmo nome das respectivas classes; não têm tipo de retorno; podem existir mais do que um por classe (sobrecarga de métodos /overloading). Atenção ! Existe sempre um construtor implícito com o mesmo nome da classe e sem parâmetros, o qual inicializa os atributos com seus valores por defeito! Conta () {NumeroConta = 111111; saldo = 0;} Conta (long n) {NumeroConta = n; saldo = 0;} Conta (long n, double s) {NumeroConta = n; saldo = s;} 10 Noção de Encapsulamento O encapsulamento leva a observar um objecto como uma caixa preta Métodos públicos Atributos públicos Métodos privados Atributos privados 11 Encapsulamento objecto1 Estrutura de Dados privada Um objecto é uma capsula que possui: •Estrutura de dados privada •Uma API constituída por métodos públicos m1 método público 1 m2 método público2 m3 método público3 •Um conjunto de métodos privados método privado1 12 Encapsulamento em Java O Encapsulamento numa classe é feita pelo uso de palavras reservadas que estão associadas aos atributos e métodos da classe. Estes são designados por modificadores de visibilidade. São so seguintes os modificadores de visibilidade: public - permite acesso a partir de qualquer classe private - permite acesso apenas na própria classe protected - permite acesso apenas na própria classe e nas subclasses (associado a herança!) nada Nota: Um atributo ou método sem modificador de acesso é acessível a qualquer classe do mesmo package. 13 Uso dos modificadores nos Atributos Consequências de tornar um atributo privado Tentar aceder a um atributo privado (i.e. fora da classe) resulta em um erro de compilação! Mas como torná-lo acessível apenas para consulta (leitura)? Isto é possível definindo-se um método que retorna o atributo (na própria classe onde o atributo se encontra) Consequências de tornar um atributo publico É possível, mas viola o encapsulamento, é aceitável no caso dos atributos constantes (i.e. Com o modificador final)! 14 Modificadores de visibilidade public Atributos Métodos private Viola encapsulamento Reforça encapsulamento Proporciona Serviços aos clientes Suporta outros metodos na classe 15 Composição na definição de Classes Composição Mecanismo básico e simples de reutilização que consiste em uma classe poder usar na sua definição classes já definidas. Este mecanismo de composição consiste na possibilidade de as variáveis de instância definidas numa classe poderem ser associadas a classes já existentes. A manipulação de tais variáveis dentro da classe que se está a definir se toma simplificada, dado que apenas teremos que enviar as mensagens que activam os métodos que são disponibilizados por tais classes já definidas. Tipos de relacionamento Usa Diz-se que A usa (uses) B, sempre que uma classe, no código dos seus métodos de instância, cria e manipula objectos de outra. Contém Diz-se que a classe A contém (has) objectos da classe B, sempre que algumas variáveis de instância de A vão ter objectos que são instâncias da classe B. De B dir-se-á que é parte de (part-of) A 16 Definição de Classes Usando Composição… Definição de uma Conta bancária Requisitos Iniciais Uma conta bancária pode ter 1 ou mais titulares, sendo um deles o titular principal, do qual se conhece a morada. Cada conta possui um saldo actual e um "plafond" de crédito que pode variar de conta para conta, mas que é definido quando esta é criada. A qualquer momento é possível realizar um depósito. Um levantamento apenas pode ser realizado se a importância pedida não ultrapassar o "plafond" de crédito definido. A qualquer momento deverá ser possível saber o saldo da conta. Deverá ser possível eliminar titulares e acrescentar titulares novos. Deverá registar-se o número total de movimentos activos realizados sobre a conta, ou seja, depósitos e levantamentos. Definição de Estrutura String NumConta String morada Vector titulares int saldo int numMov int plafond 17 Definição de Classes Usando Composição… Classe Vector Classe Vector implementa uma abstracção de dados que é uma estrutura linear indexada a partir de índice 0. Idêntica ao array, mas sem limite de dimensão. Os métodos Vector (int capInicial); Vector(); void addElement (Object obj); void insertElementAt (Object obj, int index); Object clone(); boolean contains (Object obj); Object firstElement(); Object elementAt (int index); boolean remove (int index); Object [] toArray(); int size(); 18 Definição de Classes Usando Composição… import java.util.*; public class ContaBanc { // construtor public ContaBanc (String numct, String titp, String mora, int sld, int plf) { numConta = numct; morada = mora; saldo = sld >=0 ? sld : 0; plafond = plf >=0 ? plf : 0; numMov = 0; titulares = new Vector(5); this.insereTit(titp); } // variáveis de instância private private private private private private String numConta; String morada; Vector titulares; int saldo; int plafond; int numMov; 19 Definição de Classes Usando Composição… // métodos de instância public String getNumConta () { return numConta; } public String getTitular () { return (String) titulares.firstElement(); } public int getSaldo () { return saldo; } public int getNumMov() { return numMov; } public int getPlafond() { return plafond; } 20 Definição de Classes Usando Composição public Object[] getTitulares() { return titulares.toArray(); } public boolean preLevanta (int valor) { // pré-cond return (saldo + plafond) >= valor ;} void levanta (int valor) { saldo = saldo - valor; numMov = numMov +1;} // ver pré-cond public void deposita (int valor) { saldo = saldo + valor; numMov = numMov + 1;} public void insereTit (String titular) { titulares.addElement(titular); } public void alteraMorada (String mora) { morada = mora;} public void alteraPlafond (int nplaf) { plafond = nplaf;} } 21 Complementos na Definição de Classe… Uma classe pode conter sua própria estrutura de dados e os seus próprios métodos (static), para além de possuir uma definição das variáveis e métodos das suas instâncias: Variáveis de classe Representam a estrutura interna de uma classe O acesso as variáveis deverá apenas ser realizado através de métodos de classe, mantendo-se o princípio do encapsulamento. Permitem guardar na classe informações que podem dizer respeito à globalidade das instâncias criadas e que não fariam sentido colocar em qualquer outro local. Métodos de classe Implementam o comportamento de uma classe Servem para garantir o acesso e a manipulação dos valores associados às variáveis de classe 22 Complementos na Definição de Classe… Requisitos adicionais na Classe ContaBanc: Deverá ser possível possuir a cada momento o número total de contas já criadas. Deverá ser possível possuir a cada momento o somatório dos saldos das contas existentes. public class ContaBanc { // variaveis de Classe static int numContas = 0; static int saldoTotal = 0; int total = ContaBanc.getNumContas(); int saldot = ContaBanc.getSaldoTotal(); // metodos de Classe static int getNumContas() { return numContas; ContaBanc.incNumContas(); } ContaBanc.actSaldoTotal(novoSaldo); static int getSaldoTotal() { return saldoTotal ; } static void incNumContas() { numContas++; } static void actSaldoTotal(int saldo) { saldoTotal += saldo; } … 23 Complementos na Definição de Classe… // actualização do construtor public ContaBanc(String numct, String titp, String mora, int sld, int plf) { incNumContas(); numConta = numct; morada = mora; saldo = sld >=0 ? sld : 0; actSaldoTotal (saldo); plafond = plf >=0 ? plf : 0; numMov = 0; titulares = new Vector(5); this.insereTit(titp); } 24 Projecto: Contador Requisitos Iniciais: Especificar a estrutura e o comportamento de Objectos do tipo contador que satisfaçam os seguintes requisitos: Definição de Estrutura: Os contadores deverão ser contadores de tipo inteiro. Deverá ser possível criar contadores com valor inicial igual a 0. Deverá ser possível criar contadores com valor inicial igual ao valor dado como parâmetro. Deverá ser possível saber qual o valor actual de um dado contador. Deverá ser possível incrementar o contador de 1 unidade ou de um valor dado como parâmetro. Deverá ser possível decrementar o contador de 1 unidade ou de um valor dado como parâmetro. Deverá ser possível obter uma representação textual de um contador. i.e., quais deverão ser as suas variáveis de instância (os seus nomes e os seus tipos). cada contador deverá ter apenas que ser capaz de conter um valor de tipo inteiro correspondente à contagem que tal contador representa. Definição do Comportamento: Construtores de Instância Métodos de Instância 25 Definição do comportamento… Construtores de Instância Os construtores de uma classe são todos os métodos especiais que são declarados na classe e que têm por identificador o exacto nome da classe Podem ter argumentos (valores de qualquer tipo de dados) Têm como objectivo criar instâncias de tal classe que sejam de imediato manipuláveis. Os construtores, dado criarem instâncias de uma dada classe, não têm que especificar qual o seu resultado, que será sempre uma instância da respectiva classe. É possível definir mais do que um construtor de instâncias de uma dada classe, construtores que, em geral, apenas diferem nas inicializações realizadas. Métodos de Instância: <tipo de resultado> <identificador> (<pares tipo-nome >) <tipo de resultado> Tipo primitivo Nome de uma classe ( String, Date, Point, etc.) void caso o método não devolva qualquer resultado <identificador> <pares tipo-nome> lista de parâmetros formais 26 Definição do comportamento Sobrecarga de métodos Possibilidade de numa mesma classe definir métodos tendo o mesmo nome mas diferentes parâmetros formais de entrada. Os métodos construtores são métodos particulares que estão sempre em sobrecarga, dado que são mesmo obrigados a ter o mesmo nome (identificador da classe). Métodos de instância passa-se exactamente o mesmo. Em PPO métodos e mensagens são entidades distintas: mensagens são as entidades que são responsáveis pela activação da computação programada num dado método. Assim, quando se envia uma mensagem com um certo identificador e uma certa lista de argumentos a um objecto, a determinação de qual o método que deve ser executado pelo objecto receptor depende da compatibilidade entre a estrutura da mensagem recebida e as assinaturas dos métodos pelo mesmo tomados acessíveis. É escolhido para execução o método cuja assinatura corresponda à estrutura da mensagem recebida quanto ao nome, número, tipo e ordem dos parâmetros actuais de tal mensagem. 27 Implementação Classe Contador… class Contador{ //construtores Contador(){conta = 0; } Contador(int val){ conta = val;} //variáveis de instância int conta; //métodos de instância int getConta() { return conta; // interrogador - selector} void incConta() {conta = conta + 1;// modificador do estado} ... 28 Implementação Classe Contador… … void incConta(int x) {conta = conta + x;// modificador do estado} void decConta() {conta = conta - 1;// modificador do estado} void decConta(int x) { conta = conta -x; // modificador do estado} String toString() { return (new String("Contador = " + conta));} } 29 Exemplo: Classe Contador com modificadores de acesso public class Contador{ // construtores public Contador(){ conta = 0; } public Contador(int val){ conta = val; } // variáveis de instância private int conta; // métodos de instância public int getConta() { return conta; // interrogador - selector } 30 Exemplo: Classe Contador com modificadores de acesso public void incConta() { conta = conta + 1;// modificador do estado } public void incConta(int x) { conta = conta + x;// modificador do estado } public void decConta() { conta = conta - 1;// modificador do estado } public void decConta(int x) { conta = conta -x; // modificador do estado } public String toString() { return (new String("Contador = " + conta)); } } 31 Exemplo: Teste da Classe Contador public class TesteContador { // Classe de teste da Classe Contador public static void main(String args[]) { // Criação de Instâncias Contador ct1, ct2, ct3; ct1 = new Contador(); ct2 = new Contador(20); ct3 = new Contador(10); // Utilização das Instâncias int c1, c2, c3; // variáveis auxiliares c1 = ct1.getConta(); c2 = ct2.getConta(); 32 Exemplo: Teste da Classe Contador // primeira saída de resultados para verificação System.out.println("c1 = " + c1); System.out.println("c2 = " + c2); // alterações às instâncias e novos resultados ct1.incConta(); ct2.incConta(12); c1 = ct1.getConta(); c2 = ct2.getConta(); c3 = c1 + c2; System.out.println("c1 + c2 = " + c3); ct3.decConta(); ct2.decConta(5); c1 = ct2.getConta(); c2 = ct3.getConta(); c3 = c1 + c2; System.out.println("c1 + c2 = " + c3); // conversão para string e apresentação System.out.println(ct1.toString()); System.out.println(ct2.toString()); } } 33