Definição de classes em Java (introdução) PCO / PPO Departamento de Informática Faculdade de Ciências da Universidade de Lisboa Resumo ➡ Introdução à implementação de classes Java ➡ declaração de campos de instância ➡ definição de construtores ➡ definição de métodos de instância ➡ campos e métodos de classe (i.e., “estáticos”) ➡ visibilidade privada, pública e de pacote ➡ documentação de classes no formato Javadoc ➡ anotação de pré-condições 2 Conteúdo de uma classe - componentes essenciais package some_package; public class ClassName { CAMPOS DE INSTÂNCIA + CONSTRUTORES + MÉTODOS DE INSTÂNCIA + CAMPOS/MÉTODOS DE CLASSE (ESTÁTICOS) } ➡ Campos de instância: definem atributos dos objectos da classe. ➡ Construtores: definem a inicialização dos objectos da classe. ➡ Métodos de instância: métodos que conduzem operações tendo em conta os valores dos campos de instância. ➡ Campos e métodos de classe (“estáticos”): definem atributos / métodos globais à classe. 3 package pco.time; public class TimeOfDay { ... public TimeOfDay() { ... } public TimeOfDay(int h, int m) { ... } public TimeOfDay(TimeOfDay t) { ... } public int getHours() { ... } public int getMinutes() { ... } public void setHours(int h) { ... } public void setMinutes(int m) { ... } public String toString() { ... } public void advanceOneHour() { ... } public void advanceOneMinute() { ... } public boolean sameTime(TimeOfDay t) { ... } public TimeOfDay oneHourLater() { ... } public TimeOfDay oneMinuteLater() { ... } public static TimeOfDay midday() { ... } public static TimeOfDay currentTime() { ... } ... } ➡ Vamos ver como dar corpo a esta classe para representar a hora do dia com precisão de minutos. O exemplo completo está disponível no Moodle. 4 Campos de instância package pco.time; public class TimeOfDay { ... int hours; ... int minutes; ... } ➡ Campos de instância ➡ ➡ ➡ ➡ Definem os atributos de um objecto (instância) da classe. Estado de um objecto: conjunto de valores associados aos campos de instância a dado momento durante a execução Cada campo de instância é definido por um tipo e nome (único) , e outros modificadores (opcionais). No exemplo: um objecto TimeOfDay tem sempre associado um campo hours (para as horas) e um campo minutes (minutos) 5 Visibilidade private package pco.time; public class TimeOfDay { private int hours; private int minutes; ... } ➡ O modificador private (privado) limita a visibilidade dos campos ao código da classe (o inverso de public) ➡ ➡ Os campos podem ser acedidos (lidos/escritos) apenas por código definido na própria classe. Código em outra classe não poderá aceder aos campos. ➡ Encapsulamento / ocultação de informação (“information hiding”) ➡ ➡ desta forma escondem-se detalhes de implementação o interface entre código cliente e a classe não pode ser feito via declarações privadas 6 Construtores package pco.time; public class TimeOfDay { private int hours; private int minutes; ... public TimeOfDay(int h, int m) { hours = h; minutes = m; } } ➡ Construtores ➡ ➡ Definem como um objecto de uma classe é inicializado. No exemplo: campo hours inicializado com valor de h e campo minutes com o valor de m. 7 Construtores (2) package pco.time; public class TimeOfDay { ... public TimeOfDay(int h, int m) { hours = h; minutes = m; } public TimeOfDay() { hours = 0; minutes = 0; } public TimeOfDay(TimeOfDay t) { hours = t.hours; minutes = t.minutes; } } ➡ Podemos ter vários construtores. ➡ Obs. : O terceiro construtor é expresso c/acessos a campos de t . 8 Uso do operador new package pco.time; public class TimeOfDay { ... public TimeOfDay(int h, int m) { hours = h; minutes = m; } public TimeOfDay() { hours = 0; minutes = 0; } public TimeOfDay(TimeOfDay t) { hours = t.hours; minutes = t.minutes; } TimeOfDay t = new TimeOfDay(12, 30); TimeOfDay t2 = new TimeOfDay(); TimeOfDay t3 = new TimeOfDay(t); ... TimeOfDay t • 12 hours 30 minutes TimeOfDay t2 • 0 hours 0 minutes TimeOfDay t3 • 12 hours 30 minutes 9 Palavra chave this public TimeOfDay(int hours, int minutes) { this.hours = hours; this.minutes = minutes; } em alternativa a … ➡ ➡ ➡ public TimeOfDay(int h, int m) { hours = h; minutes = m; } this refere-se à instância (objecto) em contexto Analogia possível com Python: this ~ self Palavra-chave pode ser geralmente omitida no acesso a atributos, excepto p/desfazer ambiguidades entre nomes de variáveis em contexto e campos de instância (ex. variante do construtor acima). 10 Invocação entre construtores package pco.time; public class TimeOfDay { ... public TimeOfDay(int h, int m) { hours = h; minutes = m; } public TimeOfDay() { this(0,0); } public TimeOfDay(TimeOfDay t) { this(t.hours, t.minutes); } } ➡ Alternativa ao código que vimos antes … no exemplo o segundo e terceiro construtor invocam o primeiro … ➡O esquema é usado para delegar inicialização a um construtor “base”, aquele que é o mais “geral”, e assim reutilizar código … 11 Métodos de instância package pco.time; public class TimeOfDay { private int hours; private int minutes; ... public int getHours() { return hours; } public int getMinutes() { return minutes; } public void setHours(int h) { hours = h; } public void setMinutes(int m) { minutes = m; } ... ➡ Um método de instância define uma operação que pode ser invocada sobre um objecto da classe. 12 Métodos de instância (2) package pco.time; public class TimeOfDay { ... public String toString() { StringBuilder sb = new StringBuilder(); if (hours < 10) { sb.append('0'); } sb.append(hours); sb.append(':'); if (minutes < 10) { sb.append('0'); } sb.append(minutes); return sb.toString(); } } ➡ toString(): devolve representação textual no formato HH:MM. 13 Uso de métodos de instância (exemplo) Obs.: Este código pode ser definido em qualquer pacote, já que usa apenas funcionalidade declarada como public em TimeOfDay . package any_package; public class TimeOfDayClient { public static void main(String[] args) { TimeOfDay t = new TimeOfDay(9, 30); // > 9:30 int h = t.getHours(); // < 9 int m = t.getMinutes(); // < 30 System.out.println("Hours: "+ h + " Minutes: "+ m); System.out.println(t.toString()); // “09:30” t.setHours(h + 1); // > 10 t.setMinutes(m + 10); // > 40 System.out.println(t.toString()); // “10:40” } } 14 Mutabilidade package pco.time; public class TimeOfDay { private int hours; private int minutes; ... public void setHours(int h) { hours = h; } public void setMinutes(int m) { minutes = m; } ... ➡ setHours e setMinutes permitem que o estado do objecto seja alterado após construção. ➡ Objectos TimeOfDay são então mutáveis. A distinção que fazemos é a seguinte: ➡ ➡ objectos imutáveis: estado é inicializado apenas por construtores, não sendo possível alterá-lo posteriormente objectos mutáveis: estado pode ser modificado após inicialização 15 Visibilidade de pacote (“package-protected”) package pco.time; class TimeOfDay { int hours; int minutes; ... TimeOfDay(int h, int m) { hours = h; minutes = m; } ➡ Obs.: Se não usarmos nem public nem private, por omissão as declarações de campos/métodos visíveis no contexto da classe e também todas as classes que fazem parte do mesmo pacote. ➡ Se TimeOfDay tivesse a forma acima, o código cliente do “slide” anterior teria de estar definido obrigatoriamente no pacote pco.time 16 Campos e métodos de classe (“estáticos”) package pco.time; public class TimeOfDay { ... public static final int MINUTES_PER_HOUR = 60; public static final int HOURS_PER_DAY = 24; public static TimeOfDay midday() { return new TimeOfDay(12, 0); } ... } ➡ Campos e métodos de classe são declarados com o modificador static. ➡ As declarações são globais à classe, ao contrário de campos e métodos de instância. 17 Uso de campos e métodos de classe TimeOfDay t = TimeOfDay.midday(); for (int i=1; i <= TimeOfDay.MINUTES_PER_HOUR; i++) { t.advanceOneMinute(); } System.out.println( t.toString() ); ➡ Que string é impressa? ➡ Acesso a campos de classe: ➡ ➡ TimeOfDay.MINUTES_PER_HOUR System.out (definido em java.lang.System) ➡ Chamada a método de classe: ➡ TimeOfDay.midday() 18 Campos de classe e o modificador final package pco.time; public class TimeOfDay { ... public static final int MINUTES_PER_HOUR = 60; public static final int HOURS_PER_DAY = 24; public static TimeOfDay midday() { return new TimeOfDay(12, 0); } ... } ➡ O modificador final determina que os valores dos campos de classe são têm um valor fixo. Chamamos nesse caso aos campos constantes de classe. ➡ Não podemos redefinir o valor do campo. Por exemplo, a instrução seguinte causará um erro de compilação: ➡ TimeOfDay.MINUTES_PER_HOUR = 59; 19 Uso de constantes package pco.time; public class TimeOfDay { ... public void advanceOneHour() { hours ++; if (hours == HOURS_PER_DAY) { hours = 0; } } public void advanceOneMinute() { minutes ++; if (minutes == MINUTES_PER_HOUR) { minutes = 0; advanceOneHour(); } } ➡ As constantes também podem ser úteis na definição da funcionalidade da classe. 20 Campos de instância e o modificador final package pco.time; public class TimeOfDay { private final int hours; private final int minutes; ... public void setHours(int h) { hours = h; } public void setMinutes(int m) { minutes = m; } ... X X ➡ Se usarmos o modificador final para os campos de instância, a tentativa de atribuição de novos valores aos atributos dará erro de compilação. ➡ Apenas construtores podem atribuir valores a campos de instância assim declarados. 21 Convenções usuais de nomeação em Java ➡ Pacotes: identificadores em letra minúscula separados por pontos. ➡ Se o código se associar a uma determinada organização é comum usar o URL invertido do domínio WWW como nome do pacote ➡ ex. pt.ul.fc.di.pco ➡ Nomes de classes começam com maiúsculas. ➡ Nomes de campos e métodos começam com minúsculas, excepto constantes que usualmente são declaradas usando apenas maiúsculas. ➡ Convenção “camel-case”: se um nome representar a junção de duas (ou mais) palavras, cada palavra começa com maísculas. ➡ ex. classes: TimeOfDay ➡ ex. métodos/campos/variáveis: identityMatrix() numColors StringBuilder LayoutManager 22 Documentação Javadoc ➡ O utilitário javadoc permite gerar documentação HTML a partir de código fonte Java. Toda a documentação da Java API é aliás gerada dessa forma ex. http://docs.oracle.com/javase/8/docs/api/java/lang/ String.html ➡ A documentação é gerada a partir de secções de comentários começados por /** e terminados por */ 23 Documentação Javadoc (classe) /** * A class for representing the time of day * with the precision of minutes. * * @author Eduardo Marques, DI/FCUL, 2014 */ public class TimeOfDay { … } 24 Documentação Javadoc (métodos) /** * Check for equality against a given {@code TimeOfDay} * object. * @param t A {@code TimeOfDay} object * @return {@code true} if and only if {@code this} * and {@code t} represent the same time */ public boolean sameTime(TimeOfDay t) { … } 25 Documentação Javadoc (campos) /** * Value for hours. */ private int hours; 26 Anotação de pré-condições /** * Constructs a new time using supplied * values for hours and minutes. * @param h Value for hours * @param m Value for minutes */ //@requires h >= 0 && h < HOURS_PER_DAY //@requires m >= 0 && m < MINUTES_PER_HOUR public TimeOfDay(int h, int m) { hours = h; minutes = m; } ➡ Como documentação extra-Javadoc vamos empregar a anotação @requires , com o propósito de anotar pré-condições que devem ser garantidas por código cliente. ➡ Ao longo do semestre veremos outros conceitos relacionados com o paradigma de desenho-por-contrato e também formas de validar e reportar erros usando excepções. 27