ATTENZIONE: il nuovo sito di riferimento per questa guida e altre cose più o meno interessanti è il mio BLOG

Indice
Prossimo capitolo - Creare e gestire le eccezioni

Capitolo 4 - Estendere classi

Una delle caratteristiche della programmazione OO è l'ereditarietà. Personalmente trovo che questo nome sia un po' fuorviante, un termine più preciso sarebbe estensione - non a caso java usa la parola extends.

Estendere una classe significa semplicemente aggiungere dei membri alla stessa per creare una nuova classe, più "ricca", oppure ridefinirne alcuni metodi:

	class Studente
		extends Persona
	{
		private int matricola;
5
		public Studente(String nome,
				String cognome,
				String indirizzo,
				int nCivico,
10				int matricola)
		{
			super(nome,
				cognome,
				indirizzo,
15				nCivico);

			this.matricola = matricola;
		}
	}
La linea 2 indica che uno Studente estende (è) una Persona. In linea 4 è stato aggiunto il numero di matricola, inizializzato in linea 17. In linea 12 viene chiamato il costruttore della superclasse - super è un riferimento alla superclasse, analogo a this.

In java non è possibile estendere più di una classe per volta, ma è permessa l'implementazione di più interfacce:

	class Studente
		extends Persona
		implements Consumatore, Giocatore
	{
		...

Overriding

Cosa succede se nella classe derivata si definisce un metodo con lo stesso nome (e stessi parametri) di un metodo già presente nella superclasse? Semplicemente il metodo nuovo nasconde il vecchio:

	class Persona
	{
		...
		void stampa()
		{
			System.out.println("Persona " + nome );
		}
	}

	class Studente
		extends Persona
	{
		...
		void stampa()
		{
			System.out.println("Studente " + nome );
		}
	}

/** classe principale */
	class Main
	{
		public static void main(String[] args)
		{
			Persona sandro =
				new Studente("Sandro", ...);

				sandro.stampa();
		}
	}
Questo codice stampa: "Studente Sandro"; se stampa() non fosse definito in Studente, verrebbe chiamato il metodo definito in Persona, che stamperebbe "Persona Sandro".

Polimorfismo

Come detto in precedenza, uno Studente è una Persona, e può essere trattato come tale:

	Persona alfio = new Studente(...);
ovviamente in questo caso lo Studente alfio perde le sue peculiarità, e sarà accessibile solo tramite l'interfaccia della classe persona, a meno di non usare il casting:
	Studente alfio2laVendetta = (Studente) alfio;
Questo uso della superclasse o dell'interfaccia in luogo della classe viene chiamato polimorfismo (di sottotipo).

Object

La classe Object definisce alcuni metodi che vengono ereditati e/o ridefiniti dalle sue sottoclassi, ovvero tutte le classi.

Senza dubbio il metodo più usato è toString(), che fornisce una rappresentazione dell'oggetto in forma di stringa. Come esempio possiamo (ri)definire il suddetto metodo per la classe Persona:

	public String toString()
	{
		return nome + " " + cognome +
			", residente in " + indirizzo + ", " + nCivico + ".";
	}

Classi e metodi final

Una classe final non può essere estesa. Ad esempio un tentativo di estendere la classe finale java.util.Scanner di java 1.5 produce un errore in fase di compilazione:

	class S extends Scanner // NO!
	{
		...
Anche un metodo può essere final, intendendo con questo che non può essere ridefinito.

protected

Oltre ad avere "visibilità" public, private o di default (package access), un membro di una classe può avere accesso protected, ovvero può essere usato solo nelle sottoclassi oppure nello stesso package della classe.

Classi e metodi astratti

Come si è visto, le interfacce permettono di specificare il comportamento di una classe senza implementarlo. Una classe astratta è una via di mezzo tra le interfacce e le classi concrete, poiché implementa solo una parte dei metodi, lasciando gli altri abstract:

	abstract class S
	{
		void metodo1()
		{
			System.out.println("Sono metodo1.");
		}

		abstract void metodo2();
	}
Prima di poter usare dei metodi abstract vanno implementati da una sottoclasse, non necessariamente concreta:
	abstract class T extends S
	{
		void metodo2()
		{
			System.out.println("Sono metodo2.");
		}

		abstract void metodo3();
	}
	
	class U extends T	// finalmente una classe "usabile"!
	{
		void metodo3()
		{
			System.out.println("Sono metodo3.");
		}
	}
Non si possono creare oggetti di una classe astratta, ma si può fare così:
	/* oggetto di classe U usato tramite
	l'interfaccia di S (metodo3 non accessibile) */
	S s = new U();



Indice
Prossimo capitolo - Creare e gestire le eccezioni