Programmazione e analisi di dati Modulo A: Programmazione in Java
Paolo Milazzo
Dipartimento di Informatica, Universit`a di Pisa http://pages.di.unipi.it/milazzo
milazzo di.unipi.it
Corso di Laurea Magistrale in Informatica Umanistica
A.A. 2018/2019
Classi simili...
A volte in uno stesso programma ci sono classi che descrivono cose simili tra loro.
Esempio:
supponiamo di voler realizzare un programma per la gestione degli insegnamenti di un corso di laurea
per ogni insegnamento vogliamo sapere chi ` e il docente responsabile e chi sono gli studenti frequentanti
per descrivere docenti e studenti ci servono due classi: Professore e
Studente
Partiamo con la classe Studente
p u b l i c c l a s s S t u d e n t e {
p r i v a t e S t r i n g n o m e ; // n o m e e c o g n o m e p r i v a t e S t r i n g i n d i r i z z o ; // i n d i r i z z o
p r i v a t e int m a t r i c o l a ; // n u m e r o di m a t r i c o l a p r i v a t e int a n n o ; // a n n o di f r e q u e n t a z i o n e
p r i v a t e s t a t i c int u l t i m a M a t r i c o l a = 0 // v a r i a b i l e s t a t i c a // c o s t r u t t o r e
p u b l i c S t u d e n t e ( S t r i n g nome , S t r i n g i n d i r i z z o ) { t h i s. n o m e = n o m e ;
t h i s. i n d i r i z z o = i n d i r i z z o ;
// g e n e r a la m a t r i c o l a u s a n d o la v a r i a b i l e s t a t i c a t h i s. m a t r i c o l a = u l t i m a M a t r i c o l a + 1;
u l t i m a M a t r i c o l a ++;
// si a s s u m e che un n u o v o s t u d e n t e sia al p r i m o a n n o t h i s. a n n o = 1;
} ( s e g u e )
Studenti e professori (2)
( s e g u e S t u d e n t e )
// f o r n i s c e il n o m e d e l l o s t u d e n t e p u b l i c S t r i n g g e t N o m e () { r e t u r n n o m e ; } // f o r n i s c e l ’ i n d i r i z z o d e l l o s t u d e n t e
p u b l i c S t r i n g g e t I n d i r i z z o () { r e t u r n i n d i r i z z o ; } // c o n s e n t e di m o d i f i c a r e l ’ i n d i r i z z o
p u b l i c v o i d s e t I n d i r i z z o ( S t r i n g i n d i r i z z o ) { t h i s. i n d i r i z z o = i n d i r i z z o ;
}
// f o r n i s c e la m a t r i c o l a
p u b l i c int g e t M a t r i c o l a () { r e t u r n m a t r i c o l a ; } // f o r n i s c e l ’ a n n o di f r e q u e n t a z i o n e
p u b l i c int g e t A n n o () { r e t u r n a n n o ; } ( s e g u e )
( s e g u e S t u d e n t e )
// m o d i f i c a l ’ a n n o di f r e q u e n t a z i o n e p u b l i c v o i d s e t A n n o (int a n n o ) {
if ( anno >0) t h i s. a n n o = a n n o ; }
// v e r i f i c a se lo s t u d e n t e e ’ f u o r i c o r s o
p u b l i c b o o l e a n i s F u o r i c o r s o () { r e t u r n ( anno > 5 ) ; }
// s t a m p a le i n f o r m a z i o n i s u l l o s t u d e n t e p u b l i c v o i d v i s u a l i z z a () {
S y s t e m . out . p r i n t l n (" N o m e : " + n o m e );
S y s t e m . out . p r i n t l n (" I n d i r i z z o : " + i n d i r i z z o );
S y s t e m . out . p r i n t l n (" M a t r i c o l a : " + m a t r i c o l a );
S y s t e m . out . p r i n t l n (" A n n o : " + a n n o );
if ( i s F u o r i c o r s o ())
S y s t e m . out . p r i n t l n (" ( S t u d e n t e f u o r i c o r s o ) ");
e l s e
S y s t e m . out . p r i n t l n (" ( S t u d e n t e in c o r s o ) ");
S y s t e m . out . p r i n t l n ();
} }
Studenti e professori (4)
Ora ` e la volta della classe Professore
p u b l i c c l a s s P r o f e s s o r e {
p r i v a t e S t r i n g n o m e ; // n o m e e c o g n o m e p r i v a t e S t r i n g i n d i r i z z o ; // i n d i r i z z o
p r i v a t e S t r i n g c o d i c e D o c e n t e ; // c o d i c e del d o c e n t e p r i v a t e S t r i n g d i p a r t i m e n t o ; // d i p a r t . di a f f e r e n z a // c o s t r u t t o r e
p u b l i c P r o f e s s o r e ( S t r i n g nome , S t r i n g i n d i r i z z o , S t r i n g c o d i c e D o c e n t e ,
S t r i n g d i p a r t i m e n t o ) { t h i s. n o m e = n o m e ;
t h i s. i n d i r i z z o = i n d i r i z z o ;
t h i s. c o d i c e D o c e n t e = c o d i c e D o c e n t e ; t h i s. d i p a r t i m e n t o = d i p a r t i m e n t o ; }
( s e g u e )
( s e g u e P r o f e s s o r e )
// f o r n i s c e il n o m e del p r o f e s s o r e p u b l i c S t r i n g g e t N o m e () { r e t u r n n o m e ; } // f o r n i s c e l ’ i n d i r i z z o del p r o f e s s o r e
p u b l i c S t r i n g g e t I n d i r i z z o () { r e t u r n i n d i r i z z o ; } // c o n s e n t e di m o d i f i c a r e l ’ i n d i r i z z o
p u b l i c v o i d s e t I n d i r i z z o ( S t r i n g i n d i r i z z o ) { t h i s. i n d i r i z z o = i n d i r i z z o ;
} ( s e g u e )
Studenti e professori (6)
( s e g u e P r o f e s s o r e )
// f o r n i s c e il c o d i c e d o c e n t e p u b l i c S t r i n g g e t C o d i c e D o c e n t e () {
r e t u r n c o d i c e D o c e n t e ; }
// f o r n i s c e il d i p a r t i m e n t o p u b l i c S t r i n g g e t D i p a r t i m e n t o () {
r e t u r n d i p a r t i m e n t o ; }
// s t a m p a le i n f o r m a z i o n i sul p r o f e s s o r e p u b l i c v o i d v i s u a l i z z a () {
S y s t e m . out . p r i n t l n (" N o m e : P r o f . " + n o m e );
S y s t e m . out . p r i n t l n (" I n d i r i z z o : " + i n d i r i z z o );
S y s t e m . out . p r i n t l n (" C o d i c e : " + c o d i c e D o c e n t e );
S y s t e m . out . p r i n t l n (" D i p a r t i m e n t o : " + d i p a r t i m e n t o );
S y s t e m . out . p r i n t l n ();
} }
Tutto OK.... ma quanto codice Java ripetuto...
Studente e Professore hanno diverse cose in comune:
due variabili d’istanza: nome e indirizzo
alcuni metodi: getNome(), getIndirizzo() e setIndirizzo() Questi membri in effetti non descrivono caratteristiche specifiche degli studenti e dei professori
sono caratteristiche comuni di tutte le persone
Isoliamo dunque i membri condivisi di Studente e Professore in una nuova classe Persona
aggiungiamo anche un costruttore e un metodo visualizza()
Persone
Ecco la classe Persona
p u b l i c c l a s s P e r s o n a {
p r i v a t e S t r i n g n o m e ; // n o m e e c o g n o m e p r i v a t e S t r i n g i n d i r i z z o ; // i n d i r i z z o // c o s t r u t t o r e
p u b l i c P e r s o n a ( S t r i n g nome , S t r i n g i n d i r i z z o ) { t h i s. n o m e = n o m e ;
t h i s. i n d i r i z z o = i n d i r i z z o ; }
p u b l i c S t r i n g g e t N o m e () { r e t u r n n o m e ; }
p u b l i c S t r i n g g e t I n d i r i z z o () { r e t u r n i n d i r i z z o ; } p u b l i c v o i d s e t I n d i r i z z o ( S t r i n g i n d i r i z z o ) {
t h i s. i n d i r i z z o = i n d i r i z z o ; }
// v i s u a l i z z a i d a t i d e l l a p e r s o n a p u b l i c v o i d v i s u a l i z z a () {
S y s t e m . out . p r i n t l n (" N o m e : " + n o m e );
S y s t e m . out . p r i n t l n (" I n d i r i z z o : " + i n d i r i z z o );
S y s t e m . out . p r i n t l n ();
} }
Ci` o che si pu` o fare ora ` e ridefinire le classi Studente e Professore come estensioni della classe Persona
Le classi Studente e Professore erediteranno cos`ı i membri di Persona (senza doverli definire di nuovo)
tali membri saranno quindi definiti una volta sola (in Persona) Per definire una classe come estensione di un’altra si deve usare la primitiva extends
deve essere usata all’inizio della definizione della classe
p u b l i c c l a s s S t u d e n t e e x t e n d s P e r s o n a { ...
}
Estensione di una classe (2)
Terminologia:
La classe che viene estesa (es. Persona) ` e detta superclasse
La classe che estende (es. Studente) ` e detta sottoclasse
Questa terminologia ` e legata al fatto che solitamente la relazione di
estensione viene rappresentata cos`ı (superclasse sopra, sottoclassi sotto):
Cosa succede quando si crea un oggetto di una classe che ne estende un’altra?
p u b l i c c l a s s S t u d e n t e e x t e n d s P e r s o n a { ...
}
Altrove:
...
S t u d e n t e s = new S t u d e n t e ();
...
Estensione di una classe (4)
La creazione di un oggetto di una sottoclasse (es. Studente) segue i seguenti passi:
1. Viene creato un oggetto della superclasse (es. Persona)
I
tramite il costruttore di default (Persona())
I
oppure, tramite un altro costruttore richiamato esplicitamente tramite il riferimento super (simile a this...)
2. Vengono aggiunte all’oggetto le variabili della sottoclasse
3. Viene eseguito il costruttore della sottoclasse (es. Studente)
Il risultato della creazione (nella memoria Heap) di un oggetto di una
sottoclasse ` e quindi il seguente:
Nuove versioni di Studente e Professore (1)
Ridefiniamo la classe Studente
p u b l i c c l a s s S t u d e n t e e x t e n d s P e r s o n a {
p r i v a t e int m a t r i c o l a ; // n u m e r o di m a t r i c o l a p r i v a t e int a n n o ; // a n n o di f r e q u e n t a z i o n e p r i v a t e s t a t i c int U l t i m a M a t r i c o l a = 0;
// c o s t r u t t o r e ( u g u a l e a p r i m a )
p u b l i c S t u d e n t e ( S t r i n g nome , S t r i n g i n d i r i z z o ) { // c h i a m a il c o s t r u t t o r e di P e r s o n a
s u p e r( nome , i n d i r i z z o );
// i n i z i a l i z z a le a l t r e v a r i a b i l i t h i s. m a t r i c o l a = u l t i m a M a t r i c o l a + 1;
u l t i m a M a t r i c o l a ++;
t h i s. a n n o = 1;
} ( s e g u e ) }
super ` e un riferimento all’oggetto stesso (come this) ma che consente di utilizzare i costruttori e i metodi della superclasse
Ad esempio, dentro a Studente:
this(...) richiama un costruttore della classe Studente super(...) richiama un costruttore della classe Persona
NOTA: Come this(...) anche super(...) deve essere eseguito come primo comando di un costruttore.
In caso la chiamata super(...) sia omessa, viene invocato automaticamente il costruttore senza parametri della superclasse Quindi, nel costruttore della sottoclasse la chiamata super(....) pu` o essere omessa solo se:
la superclasse prevede un costruttore senza parametri (es. il
Nuove versioni di Studente e Professore (3)
( s e g u e S t u d e n t e )
p u b l i c int g e t M a t r i c o l a () { r e t u r n m a t r i c o l a ; } p u b l i c int g e t A n n o () { r e t u r n a n n o ; }
p u b l i c v o i d s e t A n n o (int a n n o ) { if ( anno >0) t h i s. a n n o = a n n o ; }
p u b l i c b o o l e a n i s F u o r i c o r s o () { r e t u r n ( anno > 5 ) ; } // s t a m p a le i n f o r m a z i o n i s u l l o s t u d e n t e
// N O T A : per r e c u p e r a r e n o m e e i n d i r i z z o d e v e u s a r e // i m e t o d i p u b b l i c i di P e r s o n a !
p u b l i c v o i d v i s u a l i z z a () {
S y s t e m . out . p r i n t l n (" N o m e : " + g e t N o m e ( ) ) ; S y s t e m . out . p r i n t l n (" I n d i r i z z o : " + g e t I n d i r i z z o ( ) ) ; S y s t e m . out . p r i n t l n (" M a t r i c o l a : " + m a t r i c o l a );
S y s t e m . out . p r i n t l n (" A n n o : " + a n n o );
if ( i s F u o r i c o r s o ())
S y s t e m . out . p r i n t l n (" ( S t u d e n t e f u o r i c o r s o ) ");
e l s e
S y s t e m . out . p r i n t l n (" ( S t u d e n t e in c o r s o ) ");
S y s t e m . out . p r i n t l n ();
} }
Il metodo visualizza() di Studente richiede due osservazioni
OSSERVAZIONE 1: nome e indirizzo sono variabili private di Persona Il fatto che Studente sia sottoclasse di Persona non la autorizza ad accedere alle variabili private...
CONSEGUENZE:
devo usare i metodi pubblici (se disponibili, come in questo caso) altrimenti dovrei cambiare il modificatore di visibilt` a di nome e indirizzo in Persona
I
Ma quale devo usare???
Nuove versioni di Studente e Professore (5)
Rivediamoli ancora una volta:
private Utilizzabile solo all’interno della stessa classe senza modificatore Utilizzabile solo nel package che contiene la classe
protected Utilizzabile nel package che contiene la classe, e in tutte le classi che ereditano da essa public Utilizzabile ovunque
Visto che non ho definito packages (quindi uso il package default) i casi
“senza modificatore”, protected e public sono di fatto equivalenti Ergo, se non voglio rendere completamente pubbliche le variabili di Persona devo inserire le mie classi in un package:
I
Ometter` o il modificatore per limitare la visibilt` a alle sole classi del package
I
oppure user` o protected per estendere la visibilit` a anche a sottoclassi
di Persona in altri packages
OSSERVAZIONE 2: visualizza() era gi` a stato definito in Persona Questo ` e un caso di overriding di un metodo
La sottoclasse ridefinisce (sostituendolo) un metodo della superclasse Per ottenere l’overriding di un metodo ` e necessario che la firma del metodo nella sottoclasse sia identica a quella del metodo nella superclasse!
in caso contrario avremmo overloading: entrambi i metodi (il vecchio e il nuovo) sarebbero abilitati ed eseguiti in base alla firma
ATTENZIONE: overloading e overriding di metodi sono due cose diverse:
l’overloading ` e un meccanismo che consente di avere pi` u metodi con lo stesso nome
l’overriding ` e un meccanismo che consente di sostituire un metodo di
una superclasse
Nuove versioni di Studente e Professore (7)
Ridefiniamo anche la classe Professore
p u b l i c c l a s s P r o f e s s o r e e x t e n d s P e r s o n a { p r i v a t e S t r i n g c o d i c e D o c e n t e ;
p r i v a t e S t r i n g d i p a r t i m e n t o ;
p u b l i c P r o f e s s o r e ( S t r i n g nome , S t r i n g i n d i r i z z o , S t r i n g c o d i c e D o c e n t e ,
S t r i n g d i p a r t i m e n t o ) { s u p e r( nome , i n d i r i z z o );
t h i s. c o d i c e D o c e n t e = c o d i c e D o c e n t e ; t h i s. d i p a r t i m e n t o = d i p a r t i m e n t o ; }
p u b l i c S t r i n g g e t C o d i c e D o c e n t e () { r e t u r n c o d i c e D o c e n t e ; } p u b l i c S t r i n g g e t D i p a r t i m e n t o () { r e t u r n d i p a r t i m e n t o ; } p u b l i c v o i d v i s u a l i z z a () {
S y s t e m . out . p r i n t l n (" N o m e : P r o f . " + g e t N o m e ( ) ) ; S y s t e m . out . p r i n t l n (" I n d i r i z z o : " + g e t I n d i r i z z o ( ) ) ; S y s t e m . out . p r i n t l n (" C o d i c e : " + c o d i c e D o c e n t e );
S y s t e m . out . p r i n t l n (" D i p a r t i m e n t o : " + d i p a r t i m e n t o );
S y s t e m . out . p r i n t l n ();
} }
Per concludere, un main:
p u b l i c c l a s s U s a S t u d e n t e P r o f e s s o r e { p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {
P e r s o n a x = new P e r s o n a (" G i n o "," Via M i l a n o 10 ");
x . v i s u a l i z z a ();
S t u d e n t e s1 = new S t u d e n t e (" C a r l o B i a n c h i "," Via G a r i b a l d i 71 ");
s1 . v i s u a l i z z a ();
S t u d e n t e s2 = new S t u d e n t e (" M a r i o R o s s i "," Via M a z z i n i 11 ");
s2 . v i s u a l i z z a ();
P r o f e s s o r e p1 = new P r o f e s s o r e (" M a r i o R o s s i ",
" Via M a r c o n i 10 ", " a 1 1 2 3 ",
" D i p a r t i m e n t o di I n f o r m a t i c a ");
p1 . v i s u a l i z z a ();
P r o f e s s o r e p2 = new P r o f e s s o r e (" L u i g i V e r d i ",
" Via V e r d i 70 "," a 9 5 2 1 ",
" D i p a r t i m e n t o di B i o l o g i a ");
p2 . v i s u a l i z z a ();
}