Sei sulla pagina 1di 29

Tipi di dato e metodi

I tipi di dato che abbiamo visto nora in Java sono:

I i tipi di dato base (int, double, char, boolean, etc.);


I le strutture dati omogenee array modimensionali e
bidimensionali (implementati come oggetti particolari);

I la classe predenita String, i cui oggetti sono le stringhe


(istanze della classe).

È possibile denire operazioni su dati appartenenti a questi tipi di


dato denendo dei metodi, che possono essere

I metodi statici o di classe

I metodi d'istanza
Metodi
I metodi che abbiamo denito nora sono statici. La loro
intestazione si caratterizza per la presenza della parola riservata
static. La chiamata (invocazione) di un metodo statico è scritta
come segue:

nomeClasse.nomeMetodo(ListaParametri)

Finora non abbiamo denito metodi d'istanza, ma ne abbiamo


utilizzato qualcuno, e.g. alcuni metodi predeniti nella classe
String (charAt, length, equals, etc.).
Nell'intestazione di un metodo d'istanza non compare nulla al posto
della parola static.
La chiamata di un metodo d'istanza è scritta come segue:

oggetto.nomeMetodo(ListaParametri)
L'oggetto prima del punto è detto parametro implicito , mentre i
parametri tra parentesi sono i parametri espliciti del metodo.
Classi

Finora abbiamo considerato una classe come una collezione di


metodi (statici).

D'ora in avanti useremo le classi per denire nuovi tipi di dato .


Un oggetto è un' istanza di una classe.

I tipi di dato deniti tramite classi hanno oggetti che sono:

I strutturati (si dichiara la struttura degli oggetti della classe,


i.e. quali caratteristiche e/o funzionalità ha ogni oggetto);

I eterogenei (ogni oggetto di una classe è caratterizzato da più


caratteristiche, eventualmente di tipi diversi).

L'utente può denire nuovi tipi tramite il concetto di classe


( user-dened types ).
Programmazione strutturata
Un obiettivo della programmazione è scrivere programmi
comprensibili.

Approccio alla programmazione basato su:

I Divide et Impera (suddividere un problema in sottoproblemi più


piccoli, eventualmente in cascata, e risolverli separatamente);

I modularità (moduli come sottoprogrammi, funzioni e/o


procedure, metodi) =⇒ programmazione strutturata;
I protocolli semplici e chiari per gestire l' interazione tra moduli
=⇒ chiamata di metodi + passaggio dei parametri +
restituzione del risultato della computazione.

Ciò porta ad una maggiore leggibilità e comprensibilità del


programma che rende più agevole lo sviluppo del programma,
testing e debugging (individuazione di errori) e la sua
manuntenzione.
Programmazione strutturata dei dati
Oltre a strutturare le operazioni sui dati, un altro obiettivo della
programmazione è trattare dati complessi, ovvero sviluppare una
programmazione strutturata anche per i dati.

Per ottenere ciò, saranno introdotti concetti come classi e


sottoclassi, ereditarietà, information hiding, incapsulamento dei
dati, overriding, riutilizzo del codice etc.

Problematiche:

- visibilità dei dati e problemi di consistenza dei dati (sicurezza);


- aggiornamento dei dati e controllo di un solo modulo o dell'intero
programma;
- approccio basato sui Tipi di Dato Astratti : tipo/classe denita
con interfaccia pubblica ed implementazione nascosta
(incapsulamento dei dati).
Programmazione strutturata dei dati (cont.)

Altre problematiche:

- denizione di sottotipi in modo essibile: ridenizione di dati e


operazioni su tali dati (analisi top-down, ereditarietà, riutilizzo del
codice);
- costrutti per la denizione e gestione di dati complessi, strutturati
ed eterogenei, in modo sicuro e essibile (tipo di dato strutturato).
Esempi: record (Pascal, ...), struct (C, ...), tipi prodotto (ling.
funzionali), classi (Java, C++, ...)

L'approccio orientato agli oggetti è basato su oggetti (i.e. strutture


con dati e metodi per operare sui dati), stabilisce le relazioni tra
oggetti e costruisce una gerarchia.
Denizione di classe
Una possibile denizione di classe è la seguente (Bertacca-Guidi):
una classe è un gruppo di cose o individui caratterizzati da
medesime qualità e/o comportamenti.

Esempi: studente, veicolo, conto bancario, etc.

Obiettivo: denire in Java una classe che codica un insieme di


elementi aventi tutti determinate caratteristiche e/o funzionalità.

Esempio (studente universitario)

Scrivere una classe StudUniv per gli studenti universitari, i cui


oggetti sono caratterizzati semplicemente da nome, cognome e
matricola. Denire i costruttori della classe ed i metodi per
restituire i valori delle variabili istanza e le informazioni relative ad
uno studente.
Denizione di classe: linee guida

1. Individuare le caratteristiche degli elementi appartenenti ad un


insieme =⇒ Variabili istanza o campi o membri o attributi
Per ogni variabile istanza occorre ssare:

I nome (identicatore);

I tipo con cui viene implementata;

I accesso/visibilità: noi useremo sempre il modicatore di


accesso private, quindi le variabili istanza saranno accessibili
solo all'interno della classe in cui sono denite.

I metodi di una classe vedono le variabili istanze della stessa


classe.
Denizione di classe: linee guida (cont.)
2. Creazione delle istanze della classe (oggetti) + inizializzazione
delle variabili istanza =⇒ Costruttori (almeno 1!)
Per ogni costruttore abbiamo:

I nome del costruttore = nome della classe;

I è denito public;
I è un metodo speciale (NO tipo del risultato);

I può avere parametri espliciti;

I è polimorco (se si ha più di un costruttore, i parametri sono


in numero e/o tipo diverso);

I serve per creare oggetti della classe con new + dichiarazione di


riferimenti a oggetti;

I inizializzazione di default delle var. istanza (se non specicate


nel costruttore o nella denizione delle var. istanza).
Denizione di classe: linee guida (cont.)
3. Operazioni per manipolare gli oggetti della classe
=⇒ Metodi d'istanza
Per ogni metodo abbiamo:

I è denito public;
I può essere un metodo accessorio (restituisce un valore) o
modicatore (metodo di tipo void);

I NO metodi misti (i.e. metodi accessori + eetti collaterali);

I il parametro implicito sempre riferito dalla parola riservata


this;
I selezione della variabile istanza di un oggetto.

N.B. L'ordine di denizione di variabili istanza, costruttori e metodi


all'interno della classe è indierente.
La classe StudUniv: variabili istanza

Denizione delle variabili istanza nome, cognome e matricola:

public class StudUniv {

private String nome , cognome ;


private int matricola ;

// continua ...
La classe StudUniv: costruttori
Denizione di due costruttori:

// classe StudUniv continua ...


public StudUniv ( String nome , String cognome ) {
this . nome = nome ;
this . cognome = cognome ;
}

public StudUniv ( String nome , String cognome ,


int m ) {
this . nome = nome ;
this . cognome = cognome ;
this . matricola = m;
}

// continua ...
La classe StudUniv: metodi

Denizione dei metodi che restituiscono i valori delle var. istanza:

// classe StudUniv continua ...


public String leggiNome () {
return this . nome ;
}

public String leggiCognome () {


return this . cognome ;
}

public int leggiMatricola () {


return this . matricola ;
}
// continua ...
La classe StudUniv: metodi (cont.)

Denizione di altri metodi:

// classe StudUniv continua ...


public void aggMatricola ( int m) {
if ( this . matricola == 0)
this . matricola = m;
}

public String info () {


return this . cognome +" "+ this . nome +
" ( matr . "+ this . matricola + ")" ;
}

} // fine classe StudUniv


Una classe di test

Un breve programma di prova che illustra l'uso della classe


StudUniv e dei suoi metodi.

public class StudUnivTest {

public static void main ( String [] args ) {


StudUniv s1 = new StudUniv ( " Andrea " ," Rossi " ,
134678);
StudUniv s2 = new StudUniv ( " Elena " ," Bianchi " );

// continua ...
Una classe di test (cont.)

// class StudUnivTest continua ...

System . out . println ( s1 . info ());


System . out . println ( s2 . info ());

s2 . aggMatricola (149987);
System . out . println (" Dopo l ' aggiornamento
della matricola : " );
System . out . println ( s2 . info ());

}
Una classe di test (cont.)

Il risultato di tale programma di prova è la seguente stampa:

Rossi Andrea ( matr . 134678)


Bianchi Elena ( matr . 0)
Dopo l ' aggiornamento della matricola :
Bianchi Elena ( matr . 149987)
Classe BankAccount
Scrivere una classe BankAccount per i conti bancari, i cui oggetti
sono caratterizzati semplicemente dal saldo del conto.
Denire i costruttori della classe ed i metodi per depositare e
prelevare denaro, aggiungere eventuali interessi, trasferire denaro da
un conto ad un altro, etc.

public class BankAccount {


private double balance ;

public BankAccount () {
this . balance = 0;
}

public BankAccount ( double initialBalance ) {


this . balance = initialBalance ;
}
// continua ...
Classe BankAccount (cont.)

// class BankAccount continua


public double getBalance () {
return this . balance ;
}

public void deposit ( double amount ) {


this . balance += amount ;
}

public void withdraw ( double amount ) {


if ( this . balance >= amount )
this . balance -= amount ;
}

// continua ...
Classe BankAccount (cont.)

// class BankAccount continua

public void monthlyFee () {


final double Fee = 10;
this . withdraw ( Fee );
}

public void updateBalance ( double interestRate ) {


double interest =
this . balance * interestRate /100;
this . deposit ( interest );
}

// continua ...
Classe BankAccount (cont.)
// class BankAccount continua
public void transfer ( BankAccount a ,
double amount ) {
this . withdraw ( amount ); // attenzione !
a. deposit ( amount );
}

public BankAccount chooseAccount


( BankAccount a) {
if ( this . balance > a. balance )
return this ;
else
return a;
}

} // fine classe
Una classe di test

public class BankAccountTest {

public static void main ( String [] args ) {

BankAccount a = new BankAccount (10000);


a. updateBalance (5);
System . out . println (" Il saldo dopo un anno
e ' di Euro "+ a . getBalance ());

BankAccount b = new BankAccount (200);


a. transfer (b ,500);

// continua ...
Una classe di test (cont.)

// class BankAccountTest continua ...

BankAccount c = a . chooseAccount ( b );
c. monthlyFee ();

System . out . println (" Saldo di a = "+


a. getBalance ());
System . out . println (" Saldo di b = "+
b. getBalance ());
System . out . println (" Saldo di c = "+
c. getBalance ());
}

} // fine classe
Una classe di test (cont.)

Il risultato di tale programma di prova è la seguente stampa:

Il saldo dopo un anno e ' di Euro 10500.0


Saldo di a = 9990.0
Saldo di b = 700.0
Saldo di c = 9990.0
La classe Object

Ogni classe è una estensione o sottoclasse della classe Object,


madre di tutte le classi in Java.

La classe Object contiene vari metodi, tra cui i seguenti:

- public boolean equals(Object obj)


- public String toString()
Il metodo equals in Object restituisce true se due oggetti sono
lo stesso oggetto.
Quindi il confronto con equals coincide con l'operatore ==.
Abbiamo visto il metodo equals ridenito (overriding ) nella classe
String per il confronto tra stringhe.

Tipicamente, due oggetti sono considerati equals se sono istanze


della stessa classe e hanno uguale contenuto, ovvero valori
equivalenti per ogni variabile d'istanza.
Il metodo toString()

Il metodo toString() restituisce una rappresentazione testuale


dell'oggetto (su cui è invocato) in forma di stringa.

È un metodo molto utile, ad esempio, per la stampa.


N.B. toString() non è di tipo void, non stampa una stringa, ma
restituisce una stringa.
Il metodo public String info() nella classe StudUniv svolge il
ruolo del metodo toString().
Il metodo toString() di Object non è stato ridenito nella classe
StudUniv (il nome del metodo è diverso, i.e. info()).
È però possibile invocare toString() su un oggetto della classe
StudUniv, in quanto tale metodo è ereditato dalla classe Object.
Il metodo toString() (cont.)

Consideriamo l'oggetto:

StudUniv s1 = new StudUniv ( " Andrea " ," Rossi " ,


134678);
Abbiamo visto che il comando

System . out . println ( s1 . info ());


stampa la stringa Rossi Andrea (matr. 134678).
Invece, se viene invocato il metodo toString() su s1 con

System . out . println ( s1 . toString ());


viene stampato un valore StudUniv@33c7353a, dato dal nome
della classe + la rappresentazione esadecimale dell'indirizzo in
memoria dell'oggetto riferito da s1. Ciò è dovuto al fatto che la
classe Object non può conoscere la struttura dell'oggetto.
Il metodo toString() (cont.)
Se il metodo toString() di Object viene ridenito (i.e.,
sovrascritto ) StudUniv (per questo basta rimpiazzare
nella classe
l'identicatore del metodo info() con toString()), quindi

public String toString () {


return this . cognome +" "+ this . nome +
" ( matr . "+ this . matricola + ")" ;
}
il comando

System . out . println ( s1 . toString ());


stampa la stringa

Rossi Andrea ( matr . 134678)


in quanto su s1 (di tipo StudUniv) ora viene eseguito il metodo
toString() della classe StudUniv.
Il metodo toString() (cont.)
Non solo ...

Avendo ridenito toString() in StudUniv, è possibile utilizzare il


solo riferimento s1 al posto di una stringa, ovvero scrivere
System . out . println ( s1 );
Il compilatore invoca automaticamente il metodo toString() su
s1 e si ottiene la stampa della stessa stringa

Rossi Andrea ( matr . 134678)

Si possono anche concatenare (i riferimenti a) gli oggetti, e.g.

System . out . println ( s1 + " - " + s2 );


stampa la stringa

Rossi Andrea ( matr . 134678) - Bianchi Elena


( matr . 0)