Sei sulla pagina 1di 32

Herana Objetivos do captulo Aprender sobre herana Entender como herdar e sobrescrever mtodos de superclasses.

s. Ser capaz de invocar construtores de superclasses. Aprender sobre controle de acesso protegido e de pacote. Entender a superclasse comum Object e sobrescrever seus mtodos toString, equals e clone.

11.1 Uma Introduo Herana Herana um mecanismo para melhorar classes de trabalho existentes. Se precisarmos implementar uma nova classe e uma classe que representa um conceito mais geral j est disponvel, ento a nova classe pode herdar da classe existente. Por ex., suponha que tenhamos de definir uma classe SavingsAccount para modelar uma conta que paga uma taxa fixa de juros sobre os depsitos. J temos uma classe BankAccount, e uma poupana um caso especial de uma conta bancria. Nesse caso, faz sentido usar a construo de herana da linguagem. A seguir, temos a sintaxe da definio da classe:
public class SavingsAccount extends BankAccount { novos mtodos novos campos de instncia }

Na definio da classe SavingsAccount ns especificamos apenas novos mtodos e campos de instncia. Todos os mtodos e campos de instncia da classe BankAccount so automaticamente herdados pela classe SavingsAccount. Por ex., o mtodo deposit automaticamente se aplica a contas de poupana:
SavingsAccount collegeFund = new SavingsAccount(10); // conta poupana com juros de 10% collegeFund.deposit(500); // Sim, podemos usar o mtodo de BankAccount com o objeto de SavingsAccount }

J tivemos contato com herana no Cap.4, onde nossos applets todos pertenciam a classes que herdaram da classe Applet. A classe mais geral chamada de superclasse. A classe mais especializada que herda da superclasse chamada de subclasse. Temos de introduzir mais termos aqui. A classe mais geral que forma a base para herana chamada de superclasse. A classe mais especializada que herda da superclasse chamada de subclasse. Em nosso exemplo, BankAccount a superclasse e SavingsAccount a subclasse. Toda classe estende a classe Object direta ou indiretamente. Em Java, toda classe que no estenda especificamente uma outra classe uma subclasse da classe Object. Por ex., a classe BankAccount estende a classe Object. A classe Object tem um pequeno nmero de mtodos que fazem sentido para todos os objetos, como o mtodo toString, que podemos usar para obter um string que descreva o estado de um objeto.

A Fig.1 apresenta um diagrama de classes mostrando o relacionamento entre as trs classes Object, BankAccount e SavingsAccount. Em um diagrama de classe, indica-se a herana por meio de uma seta slida com uma ponta em forma de tringulo vazio que aponta para a superclasse.

Talvez voc esteja se perguntando qual a diferena entre herana e a implementao de interface. Uma interface no uma classe. Ela no tem estado, nem comportamento. Ela meramente nos informa quais mtodos devemos implementar. A superclasse tem estado e comportamento e as subclasses os herdam. Uma vantagem da herana a reutilizao de cdigo. Uma importante razo para se usar herana a reutilizao de cdigo. Ao herdar de uma classe existente, no precisamos repetir o esforo que foi feito para se projetar e aperfeioar essa classe. Por ex., ao implementar a classe SavingsAccount, podemos nos valer dos mtodos withdraw, deposit e getBalance da classe BankAccount sem tocar neles. Quando definimos uma subclasse, especificamos campos de instncia adicionais, mtodos adicionais e mtodos alterados ou redefinidos. Vamos ver como nossos objetos da poupana so diferentes dos objetos de BankAccount. Iremos configurar uma taxa de juros no construtor e ento precisaremos de um mtodo para aplicar esses juros periodicamente. Isto , alm dos trs mtodos que podem ser aplicados a qualquer conta, h um mtodo adicional addInterest (somarJuros). Esses novos mtodos e campos de instncia tem de ser definidos na subclasse.
public class SavingsAccount extends BankAccount { public SavingsAccount(double rate){ //implementao do construtor } public void addInterest(){ //implementao do mtodo }

private double InterestRate; }

A Fig.2 mostra o leiaute de um objeto SavingsAccount. Ele herda o campo de instncia balance (saldo) da superclasse BankAccount, e ganha um campo de instncia adicional: interestRate (taxa de juros). Em seguida, temos de implementar o novo mtodo addInterest (acrescentar juros). Esse mtodo calcula os juros devidos ao saldo atual e deposita esses juros na conta.
public class SavingsAccount extends BankAccount { public SavingsAccount(double rate){ //implementao do construtor InterestRate = rate; } public void addInterest(){ //implementao do mtodo double interest = getBalance() * InterestRate / 100; deposit(interest); } private double InterestRate; }

Observe como o mtodo addInterest chama os mtodos getBalance e deposit da superclasse. Como nenhum objeto especificado para as chamadas a getBalance e deposit, as chamadas se aplicam ao parmetro implcito do mtodo addInterest. Em outras palavras, os comandos a seguir so executados:
double interest = this.getBalance() * this.interestRate / 100; this.deposit(interest);

Por ex., se chamamos


collegeFund.addInterest();

ento as seguintes instrues so executadas:


double interest = collegeFund.getBalance() * collegeFund.interestRate / 100; collegeFund.deposit(interest);

Erro Frequente 11.1 Confundindo Superclasses e Subclasses Se compararmos um objeto do tipo SavingsAccount com um objeto do tipo BankAccount, ento descobriremos que A palavra-chave extends sugere que o objeto SavingsAccount uma verso estendida de um BankAccount. O objeto SavingsAccount maior, ele tem um campo de instncia interestRate que foi adicionado. O objeto SavingsAccount mais capaz; ele tem um mtodo addInterest. Ele parece ser um objeto superior em todos os aspectos. Ento, por que SavingsAccount chamado de subclasse e BankAccount de superclasse? A terminologia super/sub vem da teoria dos conjuntos. Olhe para o conjunto de todas as contas bancrias. No so todas objetos de SavingsAccount; algumas constituem outros tipos de contas bancrias. Portanto, o conjunto de objetos SavingsAccount um subconjunto do conjunto de todos os objetos BankAccount, enquanto o conjunto de objetos BankAccount um superconjunto do conjunto de objetos SavingsAccount. Os objetos mais especializados no subconjunto tm estados mais ricos e maiores recursos.

11.2 Hierarquias de Herana Na vida real, frequentemente categorizamos conceitos em hierarquias. Hierarquias so frequentemente representadas como rvores, com os conceitos mais gerais na raiz da hierarquia e os mais especializados nos galhos. A Fig.3 mostra um exemplo tpico.

Em Java, igualmente comum agrupar classes em hierarquias complexas de herana. As classes que representam os conceitos mais gerais esto prximas da raiz e as mais especializadas nos ramos. Por ex., a Fig.4 nos mostra uma parte da hierarquia de componentes de interface com o usurio do Swing em Java.

Fig.4 Parte da hierarquia dos componentes de interface com o usurio do swing. Ao projetar uma hierarquia de classes, temos de nos perguntar quais caractersticas e que comportamento so comuns a todas as classes a todas as classes que estamos projetando. Essas propriedades comuns so

coletadas em uma superclasse. Por ex., todos os componentes de interface com o usurio tem uma largura e uma altura, e os mtodos getWidth e getHeight da classe JComponent retornam as dimenses do componente. Propriedades mais especializadas podem ser encontradas em subclasses. Por ex., botes podem ter rtulos de texto e de cones. A classe AbstractButton, e no a superclasse JComponent, tem mtodos para configurar e obter o texto e o cone do boto, e campos de instncia para armazen-los. As classes individuais de botes (como JButton, JRadioButton e JCheckBox) herdam essas propriedades. Na verdade, a classe AbstractButton foi criada para expressar o que h de comum entre esses botes. Usaremos um exemplo mais simples de hierarquia em nosso estudo sobre conceitos d herana. Vamos considerar um banco que oferece os seguintes tipos de contas a seus clientes: 1. A conta corrente no paga juros, lhe d um pequeno nmero de transaes gratuitas por ms e cobra uma taxa por transao adicional. 2. A conta poupana rende juros que so capitalizados mensalmente. Em nossa, implementao, os juros so calculados usando o saldo do ltimo dia do ms, o que um tanto quanto irreal. Tipicamente, os bancos usam a mdia ou o saldo dirio mnimo. O exerccio P11.1 solicita que voc implemente essa melhoria. A Fig.5 mostra a hierarquia de herana. O Exerc. P11.2 solicita que voc acrescente outra classe a essa hierarquia.

A seguir, vamos determinar o comportamento dessas classes. Todas as contas bancrias suportam o mtodo getBalance, o qual simplesmente informa o saldo atual. Elas tambm suportam os mtodos deposit e withdraw, embora os detalhes de implementao sejam diferentes. Por ex., uma conta corrente tem de armazenar o n de transaes para poder cobrar as taxas de transaes. O depsito a prazo fixo tem de rejeitar retiradas diferentes do saldo total. A conta corrente necessita de um mtodo deductFees para deduzir as taxas mensais e para re-inicializar o contador de transaes. Os mtodos deposit e withdraw tem de ser redefinidos para contar as transaes. A poupana necessita de um mtodo addInterest para somar os juros. 11.3 Herdando Campos e Mtodos de Instncia Quando formamos uma subclasse a partir de uma dada classe, podemos especificar campos de instncia e mtodos adicionais. Nesta seo, discutiremos esse processo em detalhes. Vamos primeiramente ver os mtodos. Ao definir os mtodos de uma subclasse, h trs possibilidades. 1. Podemos sobrescrever mtodos da superclasse. Se especificarmos um mtodo com a mesma assinatura (i.e., o mesmo nome e os mesmos tipos de parmetros), ele sobrescreve o mtodo com o mesmo nome da superclasse. Sempre que o mtodo for aplicado a um objeto do tipo da subclasse, o mtodo que sobrescreve, e no o mtodo original, ser executado. Por ex., CheckingAccount.deposit sobrescreve BankAccount.deposit.

2. Podemos herdar mtodos da superclasse. Se no sobrescrevermos explicitamente um mtodo da superclasse, ns automaticamente o herdamos. O mtodo da superclasse pode ser aplicado aos objetos da subclasse. Por ex., a classe CheckingAccount herda o mtodo BankAccount.getBalance. 3. Podemos definir novos mtodos. Se definirmos um mtodo que no existia na superclasse, ento o novo mtodo s pode ser aplicado a objetos da subclasse. Por ex., CheckingAccount.deductFees um novo mtodo que no existe na superclasse BankAccount. A situao dos campos de instncia bem diferente. No podemos sobrescrever campos de instncia. Ao definir campos de instncia para uma subclasse, existem apenas dois casos: 1. Podemos herdar campos da superclasse. Todos os campos de instncia da superclasse so automaticamente herdados. Por ex., todas as subclasses da classe BankAccount herdam o campo de instncia balance. 2. Podemos definir novos campos. Quaisquer novos campos de instncia que venhamos a definir na subclasse estaro presentes apenas nos objetos da subclasse. Por ex., a subclasse SavingsAccount define um novo campo de instncia interestRate. O que acontece se definirmos um novo campo com o mesmo nome de um campo da superclasse? Por ex., o que acontece se definirmos outro campo com o nome de balance na classe SavingsAccount? Assim, cada objeto SavingsAccount ter dois campos de instncia com o mesmo nome. O novo campo definido na subclasse sombreia o campo da superclasse. I.e., o campo da superclasse ainda est presente, mas ele no pode ser acessado a partir dos mtodos de SavingsAccount. Sombrear campos de instncia pode gerar confuso. Agora, iremos implementar a subclasse CheckingAccount de modo que possamos ver em detalhes como mtodos e campos de instncia so herdados. Lembre-se que a classe BankAccount tem trs mtodos e um campo de instncia:
public class BankAccount { public double getBalance(){} public void deposit(double d){} public void withdraw(double d){} private double balance; }

A CheckingAccount tem um mtodo deductFees e um campo de instncia transactionCount adicionados, e ela sobrescreve os mtodos deposit e withdraw para incrementar a contagem de transaes:
public class CheckingAccount extends BankAccount{ public void deposit(double d){} public void withdraw(double d){} public void deductFees(){} private int transactionCount; }

Cada objeto da classe CheckingAccount tem dois campos de instncia: balance (herdado de BankAccount) transactionCount (novo para CheckingAccount) Podemos aplicar quarto mtodos aos objetos de CheckingAccount: getBalance() (herdado de BankAccount)

deposit (double) (sobrescreve mtodo de BankAccount) withdraw (double) (sobrescreve mtodo de BankAccount) deductFees () (novo para CheckingAccount) A seguir, vamos implementar esses mtodos. O mtodo deposit incrementa o contador de transaes e deposita o dinheiro:
public class CheckingAccount extends BankAccount{

public void deposit(double amount){ transactionCount++; // agora soma amount ao saldo balance = balance + amount; // ERRO ... } ... }

Agora, temos um problema. No podemos simplesmente somar amount a balance:


public void deposit(double amount){ transactionCount++; // agora soma amount ao saldo balance = balance + amount; // ERRO ... } ... }

A subclasse no tem acesso a campos privados de sua superclasse. Embora todo objeto de CheckingAccount tenha um campo de instncia balance, esse campo de instncia

private (privado) superclasse BankAccount. Os mtodos da subclasse no tm mais direitos de acesso aos
dados privados da superclasse do que qualquer outro mtodo. Se quisermos modificar um campo privado da superclasse, temos de usar um mtodo pblico da superclasse, como todos os demais. Como podemos acrescentar a quantia do depsito ao saldo, usando a interface pblica da classe BankAccount? H um mtodo muito eficaz para isso ou seja, o mtodo deposit da classe BankAccount. De modo que temos de invocar o mtodo deposit sobre algum objeto. Sobre qual objeto? A conta corrente para a qual o dinheiro est sendo depositado i.e, o parmetro implcito do mtodo deposit da classe CheckingAccount. Como vimos no Cap.3, para invocar outro mtodo sobre o parmetro implcito, no se especifica o parmetro, mas simplesmente se escreve o nome do mtodo:
package principal; public class CheckingAccount extends BankAccount{ public void withdraw(double d){} public void deductFees(){} private int transactionCount; public void deposit(double amount){ transactionCount++; // agora soma amount ao saldo

deposit(amount);// no est completo } }

Porm, isso no funciona totalmente. O compilador interpreta


deposit(amount);

como
this.deposit(amount);

O parmetro this do tipo CheckingAccount. H mtodo chamado deposit na classe CheckingAccount. Portanto, esse mtodo ser chamado mas esse exatamente o mtodo que estamos escrevendo agora! O mtodo vai chamar a si prprio repetidas vezes e o programa trancar em uma recurso infinita (Cap.17). Use a palavra-chave super para chamar um mtodo da superclasse. Em vez disso, temos de ser mais especficos indicando que queremos invocar apenas o mtodo deposit da superclasse. Existe a palavra-chave especial super para esse fim:
public class CheckingAccount extends BankAccount{ public void deposit(double amount){ transactionCount++; // agora soma amount ao saldo super.deposit(amount); } ... }

Essa verso do mtodo deposit est correta. Para depositar dinheiro em uma conta corrente, atualize o contador de transaes e ento chame o mtodo deposit da superclasse. Os mtodos remanescentes agora so diretos.
public class CheckingAccount extends BankAccount{ public void withdraw(double amount){ transactionCount++; // agora subtrai amount do saldo super.withdraw(amount); } public void deductFees(){ if(transactionCount > FREE_TRANSACTIONS){ double fees = TRANSACTION_FEE * (transactionCount - FREE_TRANSACTIONS); super.withdraw(fees); } transactionCount = 0; } private static final int FREE_TRANSACTIONS = 3; private static final double TRANSACTION_FEE = 2.0; }

Sintaxe 11.2: Chamando um Mtodo da Superclasse


super.nomeDoMtodo(parmetros); Exemplo: public void deposit(double amount){ transactionCount++; super.deposit(amount); } Objetivo: Chamar um mtodo da superclasse em vez de chamar um mtodo da classe corrente.

Erro Frequente 11.2 Sombreando Campos de Instncia A subclasse no tem nenhum acesso aos campos de instncia privados da superclasse. Por ex., os mtodos da classe CheckingAccount no podem acessar o campo balance:
public class CheckingAccount extends BankAccount{ public void deposit(double amount){ transactionCount++; balance = balance + amount; //ERRO } }

um erro comum de iniciantes resolver esse problema acrescentando outro campo de instncia com o mesmo nome.
public class CheckingAccount extends BankAccount{ public void deposit(double amount){ transactionCount++; balance = balance + amount; //ERRO } private double balance; // NO FAA ISSO private double interestRate; }

Certamente, agora o mtodo deposit compila, mas no atualiza o saldo correto! Esse objeto de CheckingAccount tem dois campos de instncia, ambos denominados balance (Fig.6). O mtodo getBalance da superclasse recupera um deles, e o mtodo deposit da subclasse atualiza o outro.

Erro Frequente 11.3 No conseguindo Invocar o Mtodo da Superclasse Um erro comum ao estender a funcionalidade de um mtodo da superclasse esquecer o qualificador super. Por ex., para retirar dinheiro de uma conta corrente, atualize a contagem de transaes e ento retire a quantia:
public void withdraw(double amount){ transactionCount++; withdraw(amount); // Erro - deveria ser super.withdraw(amount) }

Aqui withdraw (amount) refere-se ao mtodo withdraw aplicado ao parmetro implcito do mtodo. O parmetro implcito de tipo CheckingAccount, e a classe CheckingAccount tem um mtodo withdraw, de modo que esse mtodo chamado. Naturalmente, isso apenas chama o mtodo corrente novamente, o qual vai chamar a si mesmo repetidas vezes, at que o programa fique sem memria disponvel. O que temos de fazer sermos precisos ao informar qual mtodo withdraw queremos chamar. Outro erro comum esquecer totalmente de chamar o mtodo da superclasse. Nesse caso, a funcionalidade da superclasse misteriosamente desaparece. 11.4 Construo de Subclasse Vamos definir um construtor para configurar o saldo inicial de uma conta corrente.
public class CheckingAccount extends BankAccount{ public CheckingAccount(double initialBalance){ // Constri a superclasse ... //inicializa a contagem de transaes; transactionCount = 0; } ...

} Queremos invocar o construtor BankAccount para configurar o saldo em relao ao saldo inicial. Existe uma instruo especial para chamar o construtor da superclasse a partir de um construtor da subclasse. Usamos a palavra-chave super, seguida dos parmetros de construo entre parnteses:
public class CheckingAccount extends BankAccount{ public CheckingAccount(double initialBalance){ // Constri a superclasse super(initialBalance);

//inicializa a contagem de transaes; transactionCount = 0; } ... }

Para chamar o construtor da superclasse, usamos a palavra-chave super no primeiro comando do construtor da subclasse. A palavra-chave super seguida por parnteses indica uma chamada ao construtor da superclasse. Quando usado dessa forma, a chamada ao construtor tem de ser o primeiro comando do construtor da subclasse. Se super for seguido por um ponto e o nome de um mtodo, por outro lado, indica uma chamada para um mtodo da superclasse, como vimos na seo anterior. Essa chamada pode ser feita em qualquer lugar em qualquer mtodo da subclasse. O duplo uso da palavra-chave super anlogo ao duplo uso da palavra-chave this (veja Tpico Avanado 7.4). Se um construtor da subclasse no chamar o construtor da superclasse, a superclasse construda com seu construtor default. Se a superclasse no tiver um construtor default, ento o compilador reporta um erro. Por ex., podemos implementar o construtor CheckingAccount sem chamar o construtor da superclasse. Ento, a classe BankAccount construda com seu construtor default, o qual configura o saldo para zero. Naturalmente, depois o construtor CheckingAccount tem de explicitamente depositar o saldo inicial. O mais comum, entretanto, os construtores da subclasse terem alguns parmetros que passam para a superclasse e outros que utilizam para inicializar campos da prpria subclasse.

11.5 Convertendo Subclasses em Superclasses Referncias a subclasse podem ser convertidas para referncias a superclasse. A classe SavingsAccount estende a classe bankAccount. Em outras palavras, um objeto de SavingsAccount um caso especial de um objeto de BankAccount. Portanto, podemos armazenar um referncia a um objeto de SavingsAccount em um campo de objeto de tipo BankAccount. Alm disso, todas as referncias a objeto pode ser armazenadas em uma varivel do tipo Object.
SavingsAccount collegeFund = new SavingsAccount(10); BankAccount anAccount = collegeFund; Object anObject = collegeFund;

Agora, as trs referncias a objeto armazenadas em collegeFunds, anAccount e anObject se referem ao mesmo objeto do tipo SavingsAccount (Fig.7) Entretanto, o campo anObject sabe ainda menos. No podemos nem aplicar o mtodo deposit a ele deposit no um mtodo da classe Object. A converso de um tipo subclasse para um tipo superclasse muito semelhante converso de um tipo de classe para um tipo de interface. Como vimos no Cap.9, podemos converter uma classe em uma interface que a classe implemente. Por ex., se BankAccount implementa a interface Comparable, ento podemos armazenar um objeto BankAccount (bem como qualquer objeto de uma subclasse de BankAccount) em um campo de tipo Comparable. Por que algum iria querer saber menos sobre um objeto e armazenar uma referncia em um campo de objeto de uma superclasse? Isso pode acontecer se quisermos reutilizar o cdigo que conhece a respeito da superclasse, mas no da subclasse. A seguir, temos um exemplo tpico. Considere um mtodo transfer que transfere dinheiro de uma conta para outra:
public void transfer(double amount, BankAccount other){ withdraw(amount); other.deposit(amount); }

Podemos usar esse mtodo para transferir dinheiro de uma conta bancria para outra:
BankAccount momsAccount = ...; BankAccount harrysAccount = ...; momsChecking.transfer(1000, harrysAccount);

Podemos tambm usar o mtodo para transferir dinheiro para uma CheckingAccount (conta corrente):
CheckingAccount harrysAccount = ...; momsAccount.transfer(1000, harrysChecking); // Est correto passar uma referncia a CheckingAccount (conta corrente) para um // mtodo que espera uma BankAccount (conta bancria)

O mtodo transfer espera uma referncia a um BankAccount, e ele obtm uma referncia para a subclasse CheckingAccount. Felizmente, em vez de reclamar de uma no correspondncia de tipos, o compilador simplesmente copia a referncia a subclasse harrysChecking para a referncia a superclasse other. O transfer na verdade no sabe que, nesse caso, other indica uma referncia CheckingAccount. Ele s sabe que other um BankAccount, e ele no necessita saber de mais nada. Tudo o que importa ao mtodo que o objeto other pode executar o mtodo deposit. Agora vamos acompanhar a chamada do mtodo com mais preciso. Qual mtodo deposit? O parmetro other tem tipo BankAccount, de modo que pareceria que BankAccount.deposit foi chamado. Por outro lado,

a classe CheckingAccount fornece seu prprio mtodo deposit que atualiza a contagem de transaes. O campo other na verdade refere-se a um objeto da subclasse CheckingAccount, de modo que seria adequado se o mtodo CheckingAccount.deposit fosse chamado. Conforme j vimos no Cap.9, as chamadas de mtodos so sempre determinadas pelo tipo do prprio objeto, no pelo tipo da referncia ao objeto. I.e., se o prprio objeto tem o tipo CheckingAccount, ento o mtodo CheckingAccount.deposit chamado. No importa se referncia ao objeto armazenada em um campo do tipo BankAccount. Lembre-se de que esse mecanismo chamado de vinculao tardia, e que a habilidade do campo other de referir-se a objetos de tipos variados chamada de polimorfismo. Por que no armazenamos todas as referncias a contas em variveis do tipo Object? O compilador ainda necessita do tipo BankAccount para confirmar que existem mtodos tais como deposit e withdraw. Esses mtodos so definidos apenas na classe BankAccount, e no na classe Object. O programa a seguir chama os mtodos polimrficos withdraw e deposit. Devemos calcular manualmente o que o programa deve imprimir como saldo de cada conta e confirmar se os mtodos corretos foram de fato chamados.

Arquivo BankAccount.java
package principal; /* Uma conta bancria tem um saldo que pode ser alterado por depsitos e retiradas. */ public class BankAccount {

// Constri uma conta bancria com saldo zero. public BankAccount(){ balance = 0; } /*Constri uma conta bancria com um daddo saldo. * @param initialBalance saldo inicial */ public BankAccount(double initialBalance){ balance = initialBalance; } /*Deposita dinheiro na conta bancria. * @param amount quantia a depositar */ public void deposit(double amount){

double newBalance = balance + amount; balance = newBalance; } /*Retira dinheiro da conta bancria. * @param quantia a retirar */ public void withdraw(double amount){ double newBalance = balance - amount; balance = newBalance; } public void transfer(BankAccount other, double amount){ withdraw(amount); other.deposit(amount); } /* Obtm o saldo atual da conta bancria. * @return saldo atual */ public double getBalance(){ return balance; } private double balance; }

Arquivo CheckingAccount.java
package principal; /* Uma conta corrente que cobra taxas sobre transaes. */ public class CheckingAccount extends BankAccount{ /* Constri uma conta corrente com um determinado saldo. @param initialBalance o saldo inicial */ public CheckingAccount(double initialBalance){ // Constri a superclasse super(initialBalance); //inicializa a contagem de transaes; transactionCount = 0; } public void deposit(double amount){ transactionCount++; // agora soma amount ao saldo //deposit(amount); no est completo super.deposit(amount);// agora sim. } public void withdraw(double amount){ transactionCount++; // agora subtrai amount do saldo super.withdraw(amount); } /* Deduz as taxas acumuladas e reinicializa a contagem de transaes */ public void deductFees(){ if(transactionCount > FREE_TRANSACTIONS){ double fees = TRANSACTION_FEE * (transactionCount - FREE_TRANSACTIONS); super.withdraw(fees); } transactionCount = 0; } private int transactionCount; private static final int FREE_TRANSACTIONS = 3; private static final double TRANSACTION_FEE = 2.0; }

Tpico Avanado 11.1 Classes Abstratas Quando estendemos uma classe existente, temos a opo de redefinir ou no os mtodos da superclasse. s vezes desejvel forar os programadores a redefinir um mtodo. Isso acontece quando no h um bom padro para a superclasse, e somente o programador da subclasse pode saber como programar o mtodo adequadamente. A seguir, temos um exemplo. Suponha que o First National Bank of Java decida que todo tipo de conta deve ter algumas taxas mensais. Portanto, um mtodo deductFees deve ser acrescentado classe BankAccount:
public class BankAccount { public void deductFees(){} }

Porm, o que esse mtodo deveria fazer? Naturalmente, o mtodo poderia no fazer nada. Mas nesse caso, um programador que estivesse implementando uma nova subclasse poderia simplesmente esquecer de implementar o mtodo deductFees, e a nova conta herdaria o mtodo que-no-faz-nada da superclasse. Existe uma maneira melhor: declarar o mtodo deductFees como mtodo abstrato:
public abstract void deductFees()

Um mtodo abstrato um mtodo cuja implementao no especificada.

Um mtodo abstrato no tem nenhuma implementao. Isso fora os implementadores das subclasses a especificar implementaes concretas para esse mtodo. Naturalmente, algumas subclasses podem decidir implementar um mtodo que no faz nada, mas ento isso seria escolha delas e no um padro silenciosamente herdado. No podemos construir objetos de classes com mtodos abstratos. Por ex., uma vez que a classe BankAccount tenha um mtodo abstrato, o compilador ir sinalizar uma tentativa de criar uma new BankAccount () como um erro. Naturalmente, se a subclasse CheckingAccount redefinir o mtodo deductFees e fornecer uma implementao, ento podemos criar objetos CheckingAccount. Uma classe abstrata uma classe que no pode ser instanciada. Uma classe para a qual no podemos criar objetos chamada de classe abstrata. Uma classe para a qual podemos criar objetos chamada de classe concreta. Em Java, temos de declarar todas as classes abstratas com a palavra-chave abstract:
public abstract class BankAccount { public abstract void deductFees(){}

Uma classe que defina um mtodo abstrato, ou que herde um mtodo abstrato sem redefini-lo, tem de ser declarada como abstrata. Tambm podemos declarar classes que no tenham nenhum mtodo abstrato como abstratas. Com isso, evitamos que programadores criem instncias dessa classe, mas lhes permite criar suas prprias subclasses. Observe que no podemos construir um objeto de uma classe abstrata, mas podemos ter uma referncia a objeto cujo tipo seja uma classe abstrata. Naturalmente, o verdadeiro objeto ao qual ela se refere tem de ser uma instncia de uma subclasse concreta:
BankAccount anAccount = anAccount = anAccount = anAccount; // OK new BankAccount();// Erro - BankAccount abstrata. new SavingsAccount();// OK null; // OK

A razo de usarmos classes abstratas forar os programadores a criar subclasses. Especificando certos mtodos como abstratos, evitamos o problema de criar mtodos default inteis que outros podem herdar por acidente. s classes abstratas diferem das interfaces em um aspecto importante elas podem ter campos de instncia, e podem ter alguns mtodos concretos.

Tpico Avanado 11.2


Mtodos e Classes Final No Tpico Avanado 11.1, vimos como podemos forar outros programadores a criar subclasses a partir das classes abstratas e redefinir os mtodos abstratos. Ocasionalmente, podemos querer fazer o oposto: evitar que outros programadores criem subclasses ou redefinam certos mtodos. Nessas situaes, usamos a palavra-chave final. Por ex., a classe String da biblioteca Java padro foi declarada como
public final class String{...}

Isso quer dizer que ningum pode estender a classe String. H duas razes para isso. O compilador pode gerar chamadas de mtodos mais eficientes se ele souber que no precisa se preocupar com vinculao tardia. Tambm, a classe String imutvel os objetos string no podem ser modificados por nenhum de seus mtodos. Uma vez que a linguagem Java no exige isso, os projetistas de classes o fizeram. Ningum pode criar subclasses de String: portanto, sabemos que todas as referncias a String podem ser copiadas sem o risco de alterao.

Tambm podemos declarar mtodos individuais como final:


public class MyApplet extends Applet { public final boolean checkPassword(String password){ } }

Dessa forma, ningum pode redefinir o mtodo checkPassword com outro mtodo que simplesmente retorna verdadeiro. 11.6 Controle de Acesso Java tem quatro nveis de controle de acesso a campos, mtodos e classes: acesso public acesso private acesso protected acesso de pacote (o default, quando no fornecido nenhum modificador de acesso) Um campo ou mtodo que no seja declarado como public, private ou protected pode ser acessado por todas as classes do mesmo pacote, o que geralmente no desejvel. J usamos extensivamente os modificadores private e public. As caractersticas privadas podem ser acessadas apenas pelos mtodos de sua prpria classe. Caractersticas pblicas podem ser acessadas por mtodos de todas as classes. Se no fornecermos um modificador de controle de acesso, ento, o default acesso de pacote. I.e., todos os mtodos de classes do mesmo pacote podem acessar o recurso. Por ex., se uma classe for declarada como public, ento todas as outras classes em todos os pacotes podem us-la. Mas se uma classe for declarada sem modificador de acesso, ento somente as outras classes do mesmo pacote podem us-la. O acesso de pacote um bom default para classes, mas extremamente infeliz para campos. Campos de instncia e campos estticos de classes devem sempre ser private. H algumas excees: Constantes pblicas (campos public static final) so teis e seguras. Alguns objetos, tais como System.out, precisam ser acessveis a todos os programas e portanto devem ser pblicos. Muito ocasionalmente, vrias classes em um pacote tm de colaborar muito estreitamente. Nesse caso, pode fazer sentido dar acesso de pacote a alguns campos. Mas as classes internas so geralmente uma melhor soluo exs. no Cap.19. Entretanto, um erro comum esquecer a palavra-chave private, abrindo, dessa forma, um potencial buraco na segurana. Por ex., ao tempo desta edio, a classe Window do pacote java.awt continha a seguinte declarao:
public class Window extends Container{ String warningString; }

O programador foi descuidado e no tornou o campo privado. Na verdade, no havia uma boa razo pra conceder acesso de pacote ao campo warningString nenhuma outra classe o acessa. um risco de segurana. Os pacotes no so entidades fechadas qualquer programador pode criar uma nova classe, acrescent-la ao pacote java.awt, e ganhar acesso aos campos warningString de todos os objetos Window! Na verdade, essa possibilidade preocupou tanto os implementadores Java que as verses recentes do

carregador de classes rejeitam carregar classes cujo nome de pacote inicie com java.. Nossos prprios pacotes, entretanto, no desfrutam dessa proteo. O acesso de pacote para campos raramente til, e a maioria dos campos recebem acesso de pacote por acidente porque o programador simplesmente esqueceu a palavra-chave private. Os mtodos geralmente devem ser public ou private. Os mtodos pblicos so a regra. Os mtodos privados fazem sentido no caso de tarefas que dependam da implementao, os quais s deveriam ser executadas por mtodos da mesma classe. Os mtodos com acesso de pacote podem ser chamados por qualquer outro mtodo do mesmo pacote. Isso pode, ocasionalmente, fazer sentido se o pacote consistir de um pequeno nmero de classes que colaboram estreitamente entre si, mas na maioria das vezes, simplesmente por acidente o programador esqueceu o modificador public. Recomendamos que voc no use mtodos com visibilidade de pacote. As classes e interfaces podem ter acesso pblico ou acesso de pacote. As classes que so teis para o pblico em geral devem ter acesso pblico. As classes que so usadas para fins de implementao devem ter acesso de pacote. Podemos ocult-las de forma ainda melhor transformando-as em classes internas cap.9. H alguns poucos exemplos de classes internas pblicas, como as familiares classes Ellipse.Float e Ellipse.Double. Entretanto, em geral, as classes internas devem ser privadas. Erro Frequente 11.4 Acesso de Pacote Acidental muito fcil esquecer o modificador private em campos de instncia.
public class BankAccount{ ... double balance;// O acesso de pacote aqui realmente foi intencional? }

O mais provvel que foi apenas uma falta de ateno. Provavelmente o programador nunca teve a inteno de conceder acesso a esse campo para outras classes do mesmo pacote. O compilador no ir reclamar, naturalmente. Mais tarde, algum outro programador pode tirar proveito do privilgio de acesso, por convenincia ou com ms intenes. Esse um problema srio e temos de nos habituar a examinar nossas declaraes de campos para ver se no nos esquecemos de usar o modificador private. Tpico Avanado 11.3 Acesso Protegido Recursos protegidos podem ser acessados por todas as subclasses e por todas as classes do mesmo pacote. Quando tentamos implementar o mtodo deposit da classe CheckingAccount, tivemos problemas. Esse mtodo necessitava acesso ao campo de instncia balance da superclasse. Nosso remdio foi usar os mtodos adequados da superclasse para configurar o saldo (balance). Java oferece outra soluo para esse problema. A superclasse pode declarar um campo de instncia como protected (protegido):
public class BankAccount { ... protected double balance; }

Os dados protegidos em um objeto podem ser acessados pelos mtodos da classe do objeto e por todas as suas subclasses. Por ex., CheckingAccount herda de BankAccount, de modo que seus mtodos podem acessar os campos de instncia protegidos da classe BankAccount. Alm disso, os dados protegidos podem ser acessados por todos os mtodos das classes do mesmo pacote.

Alguns programadores gostam do recurso de acesso protegido (protected) porque ele parece estabelecer um equilbrio entre proteo absoluta (tornar todos os campos privados) e totalmente sem proteo (tornar todos os campos pblicos). Entretanto, a experincia tem mostrado que campos protegidos esto sujeitos ao mesmo tipo de problemas que os campos pblicos. O projetista da superclasse no tem nenhum controle sobre os autores de subclasses. Qualquer um dos mtodos da subclasse pode corromper os dados da superclasse. Alm disso, as classes com campos protegidos so difceis de modificar. Mesmo se o autor da superclasse quisesse mudar a implementao dos dados, os campos protegidos no poderiam ser mudados, pois algum em algum lugar pode ter escrito uma subclasse cujo cdigo dependa deles. Em Java, os campos protegidos tm outro problema: so acessveis no apenas s subclasses, mas tambm a outras classes do mesmo pacote. melhor deixar todos os dados como privados. Se quisermos conceder acesso aos dados apenas aos mtodos da subclasse, temos de tornar o mtodo de acesso protegido.

11.7 Object: A Superclasse Csmica


Em Java, toda classe que no estenda outra classe automaticamente estende a classe Object. I.e., a classe Object a superclasse direta ou indireta de toda classe em Java (Fig.8). Naturalmente, os mtodos da classe Object so muito gerais. A seguir, temos os mais teis:

uma boa idia redefinirmos esses mtodos em nossas classes. 11.7.1 Sobrescrevendo o mtodo toString Devemos definir o mtodo toString para gerar um string que descreva o estado do objeto. O mtodo toString retorna uma representao de string para cada objeto. Ela usada para depurao. Por ex.,
Rectangle cerealBox = new Rectangle(5, 10, 20, 30); String s = cerealBox.toString(); /* configura s para "java.awt.Rectangle[x = 5, y = 10, width = 20, height = 30"] */

Na verdade, esse mtodo toString chamado sempre que concatenamos um string com um objeto. Vamos considerar a concatenao
"cerealBox=" + cerealBox;

De um dos lados do operador de concatenao + est um string, mas do outro est uma referncia a objeto. O compilador Java automaticamente invoca o mtodo toString para transforma o objeto em um string. Ento, ambos os strings so concatenados. Nesse caso, o resultado o string.
"cerealBox=java.awt.Rectangle[x=5, y=10, width=20, height=30]"

Isso s funciona se um dos objetos j for um string. Se tentarmos aplicar o operador + a dois objetos, no sendo nenhum deles um string, ento o compilador informa um erro. O compilador pode invocar o mtodo toString porque ele sabe que todo objeto tem um mtodo toString: toda classe estende a classe Object, e essa classe define toString. Como sabemos os nmeros tambm so convertidos para strings quando so concatenados com outros strings. Por ex.,
int age = 18; String s = "Harry's age is" + age; // configura s para "Harry's age is 18"

Nesse caso, o mtodo toString no est envolvido. Os nmeros no so objetos e no h mtodo toString para eles. Entretanto, h apenas um pequeno conjunto de tipos primitivos, e o compilador sabe como convert-los para string. Vamos tentar o mtodo toString para a classe BankAccount:
BankAccount momsSavings = new BankAccount(5000); String s = momsSavings.toString(); // configura s para algo parecido com "BankAccount@d24606bf"

Isso desencorajador tudo que impresso o nome da classe, seguido pelo endereo do objeto na memria. Queremos saber o que est dentro do objeto, porm, naturalmente, o mtodo toString da classe Object no sabe o que est dentro da nossa classe BankAccount. Portanto, temos de sobrescrever o mtodo e fornecer nossa prpria verso na classe BankAccount. Seguiremos o mesmo formato que usa o mtodo toString da classe Rectangle: primeiramente imprima o nome da classe e depois os valores dos campos de instncia dentro das chaves.

public class BankAccount { public String toString(){ return "BankAccount[balance=" + balance + "]"; } }

Assim funciona melhor:


BankAccount momsSavings = new BankAccount(5000); String s = momsSavings.toString(); // configura s para "BankAccount[balance=5000]"

Dica de Produtividade 11.1


Fornea toString em todas as Classes Se tivermos uma classe cujo mtodo toString( ) retorne um string que descreva o estado do objeto, ento podemos simplesmente chamar System.out.println(x) sempre que necessitarmos inspecionar o estado corrente de um objeto x. Isso funciona porque o mtodo println da classe PrintStream invoca x.toString( ) quando necessita imprimir um objeto. Isso extremamente til se houver um erro no nosso programa e nossos objetos no se comportarem da maneira que ns espervamos. Podemos simplesmente inserir alguns comandos de impresso e dar uma olhada dentro do estado do objeto durante a execuo do programa. Alguns depuradores podem at invocar o mtodo toString sobre objetos que estamos inspecionando. Certamente, mais complicado escrever um mtodo toString quando no temos certeza se nosso programa alguma vez precisar de um afinal de contas, ele pode simplesmente funcionar corretamente na primeira tentativa. Porm, muitos programas no funcionam na primeira tentativa. Assim que voc descobrir que o seu um deles, considere a possibilidade de acrescentar esses mtodos toString de modo que possa facilmente imprimir objetos.

Tpico Avanado 11.4


Herana e o Mtodo toString Acabamos de ver como podemos escrever um mtodo toString: forme um string que consista no nome da classe e nos nomes e valores dos campos de instncia. Entretanto, se quisermos que nosso mtodo toString seja utilizvel pelas subclasses de nossa classe, temos de trabalhar um pouco mais. Em vez de fixar no cdigo o nome da classe, devemos chamar o mtodo getClass para obter um objeto da classe Class que descreve classes e suas propriedades. Ento, invocamos o mtodo getName para obter o nome da classe:
public String toString(){ return getClass().getName() + "[balance=" + balance +"]"; }

Assim, o mtodo toString imprime o nome correto da classe quando o aplicamos a uma subclasse, digamos uma SavingsAccount.
SavingsAccount momsSavings = ...; System.out.println(momsSavings); //imprime SavingsAccount [balance=10000]

Naturalmente, na subclasse, devemos redefinir toString e acrescentar os valores dos campos de instncia da subclasse. Observe que temos de chamar super.toString para obter os valores dos campos da superclasse a subclasse no consegue acess-los diretamente.

public class SavingsAccount extends BankAccount { public String toString(){ return super.toString() + "[interestRate" + interestRate +"]"; } }

Agora, uma conta poupana convertida para um string tal como SavingsAccount[balance=10000] [interestRate=10]. As chaves mostram quais campos pertencem superclasse. 11.7.2 Sobrescrevendo o mtodo equals Devemos definir o mtodo equals para testar se dois objetos tm estados iguais. O mtodo equals chamado sempre que quisermos verificar se dois objetos tm o mesmo contedo:
if(coin1 == coin2)... // o mesmo objeto

Vamos implementar o mtodo equals para a classe Coin. Temos de redefinir o mtodo equals da classe Object:
public class Coin { ... public boolean equals(Object otherObject){ ... } }

Agora temos um pequeno problema. A classe Object no sabe nada sobre contas bancrias, de modo que ela define o parmetro otherObject do mtodo equals para ter o tipo Object. Ao redefinir o mtodo, no nos permitido mudar a assinatura do objeto. Vamos converter o parmetro para a classe Coin:
Coin other = (Coin)otherObject

Ento, podemos comparar as duas moedas (coins).

public class Coin {

public boolean equals(Object otherObject){ Coin other = (Coin)otherObject; return name.equals(other.name) && value == other.value; } }

Observe que temos de usar equals para comparar campos de objetos, mas usamos == para comparar campos numricos.

Tpico Avanado 11.5


Herana e o Mtodo equals Vimos apenas como escrever um mtodo equals: converter o parmetro otherObject para tipo de nossa classe, e ento comparar os campos do parmetro implcito e o outro parmetro. Mas e se algum chamasse coin1.equals(x) onde x no fosse um objeto Coin? Ento, a m coero geraria uma exceo, e o programa trancaria. Portanto, primeiramente queremos testar se otherObject realmente uma instncia da classe Coin. O teste mais fcil seria com operador instanceof. Entretanto, esse teste no suficientemente especfico. otherObject poderia pertencer a alguma subclasse de Coin. Para descartar essa possibilidade, devemos testar se os dois objetos pertencem mesma classe. Caso contrrio, retorne false.
if(getClass() != otherObject.getClass()) return false;

Alm disso, a especificao da linguagem Java exige que o mtodo equals que leva em conta esses dois pontos:
public class Coin {

public boolean equals(Object otherObject){ if(otherObject == null) return false; if(getClass() != otherObject.getClass()) return false;

Coin other = (Coin)otherObject; return name.equals(other.name) && value == other.value; } }

Quando formos definir equals em uma subclasse, devemos primeiramente chamar equals da superclasse, da seguinte forma:
public class CollectibleCoin extends Coin{

public boolean equals(Object otherObject){ if(!super.equals(otherObject)) return false; CollectibleCoin other = (CollectibleCoin) otherObject; return year == other.year; } private int year; }

11.7.3 Sobrescrevendo o mtodo clone O mtodo clone cria um novo objeto com o mesmo estado de um objeto existente. Vimos que copiar uma referncia a objeto simplesmente nos d duas referncias ao mesmo objeto:
BankAccount account1 = new BankAccount(1000); BankAccount account2 = account1; account2.deposit(500); // agora tanto account1 como account2 tm um saldo de 1500

O que podemos fazer se realmente queremos fazer uma cpia de um objeto? Esse o objetivo do mtodo clone. O mtodo clone tem de retornar um novo objeto que tenha estado idntico ao do objeto existente (Fig.11). A seguir temos um mtodo clone para a classe BankAccount.

this =

public class BankAccount { ... public Object clone(){ BankAccount cloned = new BankAccount(); cloned.balance = balance; return cloned; }

mais difcil definir o mtodo clone para subclasses. (Tpico Avanado 11.6) Uma vez que o mtodo clone definido na classe Object, ele no pode saber o tipo do objeto a ser retornado. Portanto, seu tipo de retorno Object. Isso no um problema quando se est implementando o mtodo clone. Mas ao chamar o mtodo, temos de usar uma coero para convencer o compilador de que account1.clone( ) realmente tem o mesmo tipo que account1. A seguir, temos um exemplo:
BankAccount account2 = (BankAccount)account1.clone();

Erro Frequente 11.6


Esquecendo de Clonar Em Java, os campos de objetos contm referncias a objetos, e no os prprios objetos. Isso pode ser conveniente para dar dois nomes ao mesmo objeto:
BankAccount harrysChecking = new BankAccount(); BankAccount slushFund = harrysChecking; // Use a conta corrente de Harry para o fundo slush("caixa2"): slushFund.deposit(8000); // uma grande soma de dinheiro vai parar na conta corrente de Harry

Entretanto, se no quisermos duas referncias ao mesmo objeto, ento isso um problema. Nesse caso, devemos usar o mtodo clone:
BankAccount slushFund = (BankAccount)harrysChecking.clone();

Dica de Qualidade 11.1


Clone Campos de Instncia Mutveis em Mtodos de Acesso Vamos considerar a classe a seguir:
public class Customer { public Customer (String aName){ name = aName; account = new BankAccount(); } public String getName(){ return name; } public BankAccount getAccount() { return account; }

private String name; private BankAccount account; }

Essa classe tem uma aparncia muito normal e sem atrativos, mas o mtodo getAccount tem uma propriedade curiosa. Ele quebra o encapsulamento, pois qualquer um pode modificar o estado do objeto sem passar pela interface pblica:
Customer harry = new Customer("Harry Handsome"); BankAccount account = harry.getAccount(); // qualquer um pode retirar dinheiro! account.withdraw(1000000);

Ser que era isso que os projetistas da classe tinham em mente? Talvez eles quisessem que os usurios da classe apenas inspecionassem a conta. Nesse caso, devemos clonar a referncia ao objeto:
public BankAccount getAccount() { return (BankAccount)account.clone();

} Ser que tambm temos de clonar o mtodo getName? No esse mtodo retorna um string e strings so imutveis. seguro fornecer uma referncia a um objeto imutvel. A regra geral que a classe deve clonar todas as referncias a objetos mutveis que ela fornecer.

Tpico Avanado 11.6


Herana e mtodo clone Vimos como clonar um objeto construindo um novo objeto com o mesmo estado:
public Object clone(){ BankAccount cloned = new BankAccount(); cloned.balance = balance; return cloned;

Esse mtodo tem uma limitao importante: ele no funciona para subclasses.
SavingsAccount momsSavings = ...; Object clonedAccount = momsSavings.clone();

O mtodo clone constri uma nova conta bancria, e no uma conta poupana! melhor usar o mtodo Object.clone para realizar a clonagem. Este mtodo cria um novo objeto de mesmo tipo do objeto original. Ele tambm copia automaticamente os campos de instncia do objeto original para o clone do objeto.
public class BankAccount { ... public Object clone(){ // incompleto Object clonedAccount = super.clone(); return clonedAccount; BankAccount cloned = new BankAccount(); cloned.balance = balance; return cloned;

} }

Entretanto, este mtodo Object.clone tem de ser usado com cuidado. Ele somente transfere o problema de clonagem por um nvel; no o resolve completamente. Especificamente, se um objeto contm um referncia a outro objeto, ento o mtodo Object.clone faz uma cpia dessa referncia a objeto, no um clone desse objeto. A Fig.12 mostra como o mtodo Object.clone funciona com um objeto Customer que tem referncias a um objeto String e a um objeto BankAccount. Como podemos ver, o mtodo Object.clone copia as referncias para o clone do objeto Customer e no clona os objetos aos quais eles se referem. Essa forma de cpia chamada de cpia superficial. H um razo para o mtodo Object.clone no clonar sistematicamente todos os subobjetos: em algumas situaes, isso desnecessrio. Por ex., se um objeto contiver uma referncia a um string, no h nenhum prejuzo em se copiar a referncia ao string, porque os objetos string de Java nunca podem mudar seus contedos. O mtodo Object.clone faz a coisa certa se um objeto contiver apenas nmeros, valores booleanos e strings. Mas ele precisa ser usado com cautela quando um objeto contiver referncias a outros objetos. Por essa razo, h duas salvaguardas embutidas no mtodo Object.clone para garantir que ele no seja usado acidentalmente. Primeiramente, o mtodo declarado protected (ver Tpico Avanado 11.3). Isso evita que ns acidentalmente chamemos x.clone( ) se a classe a qual x pertence no redefiniu clone como pblico. Como segunda precauo, Object.clone confere se o objeto que est sendo clonado implementa a interface Cloneable. Caso contrrio, ele dispara uma exceo. Ou seja, o mtodo Object.clone fica assim:
public class BankAccount { public class Object(){ protected Object clone() throws CloneNotSupportedException { if(this instanceof Cloneable) { // copia os campos de instncia } else throw new CloneNotSupportedException(); } }

Infelizmente, todas as medidas de salvaguarda indicam que os legtimos chamadores de Object.clone( ) pagam um preo eles tm de capturar essa exceo mesmo se sua classe implementar Cloneable.

public class BankAccount implements Cloneable {

public Object clone(){ try{ return super.clone(); } catch(CloneNotSupportedException e){ // no pode acontecer porque ns implementamos Cloneable // mas inda temos de captur-la return null; } } }

Se um objeto contiver uma referncia a outro objeto mutvel, ento temos de chamar clone para essa referncia. Por ex., suponha que a classe Customer tenha um campo de instncia da classe BankAccount. Ento, podemos implementar Customer.clone da seguinte maneira:
public class BankAccount implements Cloneable {

public Object clone(){ try{ Customer cloned = (Customer)super.clone(); cloned.account = (BankAccount)account.clone(); return cloned; } catch(CloneNotSupportedException e){ // no pode nunca acontecer porque ns implementamos Cloneable return null; } } private String name; private BankAccount account; }

Resumo do Captulo
1. Herana um mecanismo para estender classes existentes acrescentando mtodos e campos. 2. A classe mais geral chamada de superclasse. A classe mais especializada que herda da superclasse chama de subclasse. 3. Toda classe, direta ou indiretamente, estende a classe Object. 4. Herdar de uma classe diferente de implementar uma interface: a subclasse herda comportamentos e estados da superclasse.

5. Uma vantagem da herana a reutilizao de cdigo. 6. Ao definir uma subclasse, especificamos os campos de instncia adicionados, os mtodos adicionados e os mtodos alterados ou sobrescritos. 7. Conjuntos de classes podem formar hierarquias complexas de herana. 8. Uma subclasse no tem acesso a campos privados de sua superclasse. 9. Use a palavra-chave super para chamar um mtodo da superclasse. 10. Para chamar o construtor da superclasse, usamos a palavra-chave super na primeira instruo do construtor da subclasse. 11. As referncias a subclasses podem ser convertidas para referncias a superclasses. 12. Um mtodo abstrato um mtodo cuja implementao no especificada. 13. Uma classe abstrata uma classe que no pode ser instanciada. 14. Um campo ou mtodo que no foi declarado como public, private, nem protected pode ser acessado por todas as classes do mesmo pacote, o que geralmente no desejvel. 15. Recursos protegidos podem ser acessados por todas as subclasses e por todas as classes do mesmo pacote. 16. Deve-se definir o mtodo toString para produzir um string que descreva o estado do objeto. 17. Deve-se definir equals para testar se dois objetos tm estados iguais. 18. O mtodo clone cria um novo objeto com o mesmo estado de um objeto existente.

Potrebbero piacerti anche