Extensão de classes em Java - noções elementares PCO / PPO Departamento de Informática Faculdade de Ciências da Universidade de Lisboa Conteúdo ➡ Noções elementares de extensão de classes ➡ Exemplo: classe TimeOfDaySecs ➡ Declaração de subclasse usando extends. ➡ Implementação de construtores. ➡ Extensão, herança e reutilização de funcionalidade. ➡ Redefinição de métodos. ➡ Referência à super-classe com super. ➡ Restrições à herança com final. ➡ A anotação @Override. 2 Extensão de classes ??? public class TimeOfDaySecs . . . { ... public TimeOfDaySecs(int h, int m, int s) { ... } public int getSeconds() { ... } public void setSeconds(int s) { ... } public String toString() { ... } ... } ➡ Exemplo introdutório: definição da classe TimeOfDaySecs por extensão da classe TimeOfDay ➡ TimeOfDaySecs estende a funcionalidade de TimeOfDay, representando a hora do dia com a precisão de segundos. 3 extends public class TimeOfDaySecs extends TimeOfDay { … public static final int SECONDS_PER_MINUTE = 60; public TimeOfDaySecs(int h, int m, int s) { ... } public int getSeconds() { ... } public void setSeconds(int s) { ... } public String toString() { ... } ... } ➡ A relação de herança entre classes em Java é definida por pelo uso da palavra-chave extends na declaração de uma classe. ➡ No exemplo: TimeOfDaySecs, designada por subclasse, estende TimeOfDay, designada por super-classe. 4 Hierarquia de classes package java.lang; public class Object { … } package pco.time; public class TimeOfDay { … } public class TimeOfDaySecs extends TimeOfDay { … } ➡ Uma classe pode estender uma e uma só super-classe. ➡ ➡ ➡ Não podemos declarar mais do que uma super-classe com extends. Por omissão a super-classe é java.lang.Object (extends java.lang.Object implícito em TimeOfDay), de que iremos falar nas próximas aulas … Apenas java.lang.Object não tem super-classe: é a classe raiz da hierarquia de objectos em Java. 5 TimeofDaySecs campos de instância public class TimeOfDaySecs extends TimeOfDay { private int seconds; public TimeOfDaySecs(int h, int m, int s) { ... } ... } ➡ ➡ A classe TimeOfDay já representa o tempo em horas e minutos ... Declaramos em TimeOfDaySecs apenas um campo de instância (seconds) para representar adicionalmente os segundos. 6 TimeofDaySecs - construtor public class TimeOfDaySecs extends TimeOfDay { private int seconds; //@ requires h >= 0 && h < HOURS_PER_DAY //@ requires m >= 0 && m < MINUTES_PER_HOUR //@ requires s >= 0 && s < SECONDS_PER_MINUTE public TimeOfDaySecs(int h, int m, int s) { super(h, m); // Call superclass constructor. seconds = s; // Initialize value for seconds. } ... } ➡ Este construtor de TimeOfDaySecs inicializa o objecto em dois passos: ➡ ➡ A invocação de um construtor da classe-pai TimeOfDay. Inicialização do valor dos segundos (seconds). ➡ A palavra-chave super é usada para referência à super-classe. ➡ Um construtor de uma subclasse começa sempre por invocar construtor da super-classe. o 7 package java.lang; public class Object { public Object () { ... } ... } public class TimeOfDay { private int hours; private int minutes; public TimeOfDay(int h, int m) { super(); hours = h; Obs: super() implícito quando omitido) minutes = m; } ... } public class TimeOfDaySecs extends TimeOfDay { private int seconds; public TimeOfDaySecs(int h, int m, int s) { super(h, m); seconds = s; } ... } TimeOfDaySecs t = new TimeOfDaySecs(12, 30, 59); 8 Definição de nova funcionalidade em subclasses public class TimeOfDaySecs extends TimeOfDay { … private int seconds; public TimeOfDaySecs(int h, int m, int s) { ... } public int getSeconds() { return seconds; } //@ requires s >= 0 && s < SECONDS_PER_MINUTE public void setSeconds(int s) { seconds = s; } } ➡ Podemos definir agora ➡ nova funcionalidade na subclasse … getSeconds() / setSeconds() no exemplo 9 Herança de métodos public class TimeOfDay { ... public int getHours() { return hours; } public int getMinutes() { return minutes; } } public class TimeOfDaySecs extends TimeOfDay { ... public int getSeconds() { return seconds; } } TimeOfDaySecs t = new TimeOfDaySecs(12, 30, 59); int h = t.getHours(); int m = t.getMinutes(); int s = t.getSeconds(); ➡ ... e reutilizar funcionalidade da super-classe 10 Reutilização de funcionalidade public class TimeOfDaySecs extends TimeOfDay { ... public void advanceOneSecond() { seconds ++; if (seconds == SECONDS_PER_MINUTE) { advanceOneMinute(); // in TimeOfDay } } public class TimeOfDay { } ... public void advanceOneMinute() { minutes ++; if (minutes == MINUTES_PER_HOUR) { minutes = 0; advanceOneHour(); } } } ➡ advanceOneSecond em TimeOfDaySecs advanceOneMinute em TimeOfDay chama 11 Redefinição de métodos toString - versão 1 public class TimeOfDay { ... public String toString() { } .... } HH:MM public String toString() { StringBuilder sb = new StringBuilder(); if (getHours() < 10) sb.append('0'); sb.append(getHours()); Método toString sb.append(':'); redefinido if (getMinutes() < 10) em sb.append('0'); TimeOfDaySecs sb.append(getMinutes()); sb.append(':'); if (seconds < 10) sb.append('0'); HH:MM:SS sb.append(seconds); return sb.toString(); } 12 Redefinição de métodos (toString) - versão 2 public class TimeOfDay { ... public String toString() { } .... } HH:MM public class TimeOfDaySecs extends TimeOfDay { toString() ... chama public String toString() { implementação // Call TimeOfDay.toString(). String hhmm = super.toString(); da super-classe StringBuilder sb = new StringBuilder(hhmm); sb.append(':'); if (seconds < 10) sb.append('0'); sb.append(seconds); HH:MM:SS return sb.toString(); } } 13 Anotação @Override package java.lang; public class Object { … public String toString() { … } } public class TimeOfDay { … @Override public String toString() { … } } public class TimeOfDaySecs extends TimeOfDay { … @Override public String toString() { … } } ➡ Boa prática: A anotação opcional @Override assinala uma redefinição de método. Previne erros de programação (ex. se chamarmos ao método tostring em vez de toString não teremos uma redefinição). 14 Restrições à redefinição de métodos public class TimeOfDay { ... public final int getHours() public final void setHours(int h) public final int getMinutes() public final void setMinutes(int m) } { { { { ... ... ... ... } } } } public class TimeOfDaySecs extends TimeOfDay { ... } ➡ Devemos identificar com final os métodos que não poderão ser redefinidos por subclasses. ➡ Não seria boa ideia/prática redefinir getHours() etc em TimeOfDaySecs ... conseguimos restringir essa redefinição usando o modificador final. 15 Restrições à definição de subclasses public class TimeOfDay { ... public final int getHours() public final void setHours(int h) public final int getMinutes() public final void setMinutes(int m) } { { { { ... ... ... ... } } } } public final class TimeOfDaySecs extends TimeOfDay { ... } ➡ Por outro lado podemos aplicar final à classe TimeOfDaySecs para impedir que esta seja estendida. Nesse caso, nenhuma classe poderá ter TimeOfDaySecs como super-classe. ➡ Exemplo na API do Java: java.lang.String 16