Classi ed Oggetti in JAVA
Dott. Ing. Leonardo Rigutini
Dipartimento Ingegneria dell’Informazione
Università di Siena
Via Roma 56 – 53100 – SIENA
[email protected]
www.dii.unisi.it/~rigutini/
Outlines

Classi ed Oggetti:




Differenza
Interfaccia
Variabili oggetto e riferimento agli oggetti
Definire una classe






La dichiarazione class
Visibilità public e private
Variabili membro

le costanti : final
Metodi

i parametri espliciti ed il parametro this

costruttore ed overloading: default, copia, parametri di costruzione
Membri static

Metodi static

Variabili e costanti static
Costruttori private
Classi ed Oggetti
Oggetti

Come detto la gran parte dei programmi non è costituita solo da
numeri o stringhe ma da dati molto più complessi con proprietà e
funzioni proprie:


questi dati sono rappresentati dagli oggetti
Un oggetto è una entità che il programmatore può manipolare
all’interno del programma mediante l’invocazione di metodi :

Quando è invocato un metodo di un oggetto, vengono svolte all’interno
dell’oggetto una serie di attività con lo scopo di realizzare la funzione per
cui il metodo è stato implementato
Classi di Oggetti

Ogni oggetto è definito dal programmatore in fase di
programmazione definendo la sua classe di appartenenza.

Se per esempio si sta programmando un gioco come il 7 e mezzo, si
può immaginare di individuare le seguenti classi di oggetti:






Carta
Mazzo
Mazziere
Giocatore
Tavolo
Per ogni classe sarà necessario definire un set di variabili (ceh ne
definiscono lo stato) e un insieme di metodi per modificare o far
interagire gli oggetti tra di loro.
Classi di Oggetti

Una volta definite le classi, le loro variabili ed i metodi, si può
costruire l'applicazione creando un insieme di oggetti (dipendente
dal problema in esame) e facendoli interagire tra di loro attraverso i
metodi che ognuno di loro ha, in quanto elemento della classe
specificata in precedenza.

Per esempio:

Nel gioco del 7 e mezzo, si possono prevedere un numero variabile n di
giocatori. Questo significa che saranno istanziati n oggetti di tipo
Giocatore. Ogni giocatore ha un nome, un punteggio e un insieme di
Carte e questi valori sono memorizzati in altrettante variabili definite
nella classe Giocatore (e quindi presente in ogni oggetto giocatore
istanziato). Ogni istanza però ha un suo insieme di variabili che
contengono valori diversi (nomi diversi, carte diverse ecc...)
Classi ed oggetti

Che differenza c’è tra classe ed oggetto ?

La classe è la descrizione astratta di un tipo di dato:


Specifica cioè i metodi e le variabili che quel tipo di dato possiede
L’oggetto è una istanza della classe:

Quando istanziamo una variabile definendola di una certa classe,
noi creiamo un oggetto di quella classe rappresentato dal nome
della variabile che abbiamo istanziato
Esempio “Giocatore”

Il giocatore di 7 e mezzo
Giocatore
Nome
Cognome
Carte Iniziali
Carte Richieste
Esempio “Giocatore”

Per istanziare un oggetto di tipo Giocatore, è necessario un
processo detto di costruzione

Giocatore G=new Giocatore();
Giocatore
nome
G
Cognome
Carte Iniziali
Carte Richieste

La variabile G punta all'oggetto Giocatore creato in memoria. G è
chiamata variabile oggetto e permette di accedere all'oggetto
Esempio “Giocatore”

L'oggetto giocatore creato come in precedenza, ha i valori interni
NULLI, ovvero nessun nome e cognome, nessun insieme di carte ecc...

E' possibile creare oggetti specificando i valori iniziali delle proprietà di
ogni oggetto fornendole al processo di costruzione:

Giocatore G=new Giocatore(“Leonardo”,”Rigutini”);
Giocatore
G
nome
Leonardo
Cognome
Rigutini
Carte Iniziali
Carte Richieste
Esempio “Giocatore”

Come si può utilizzare un oggetto Giocatore?

Per ora si può fare ben poco, l'unica cosa possiamo scrivere
una applicazione che crea un giocatore e ne stampa a video il
nome e cognome:
static public int main(String[] args) {
Giocatore G=new Giocatore(“Leonardo”,”Rigutini”);
System.out.println(G.nome+ “ ” +G.cognome);
}

Con l'operatore . si accede alle proprietà dell'oggetto:

Con G.nome si vuole accedendo alla proprietà nome dell'oggetto G
Variabili oggetto

Normalmente con un oggetto dovremmo fare di più che
semplicemente crearlo, stamparlo e scordarselo

Per tenere traccia di un oggetto, è necessario associare
l’oggetto ad una variabile oggetto:
Giocatore G:

Come si vede la dichiarazione di una variabile oggetto è
costituita da due parti:
classe
nome_della_variabile;
Variabili oggetto

Per creare un oggetto ed associarlo ad una variabile

1) Fase dichiarativa separata dalla fase istanziatrice:
Giocatore G;
G=new Giocatore(“Leonardo”,”Rigutini”);

2) Fase dichiarativa ed istanziatrice insieme:
Giocatore G=new Giocatore(“Leonardo”,”Rigutini”);
Variabili oggetto non inizializzate

Nel primo caso la variabile G è dichiarata di tipo Giocatore ma non
è inizializzata. Lo sarà dopo una serie di altre istruzioni.

cosa accade se si utilizza una variabile non inizializzata?
Giocatore G;
....
System.println(G.nome);

Il compilatore si accorge di questo fatto e segnala un errore:
Giocatore: Variable G might not have been initialized at line ....
Riferimenti agli oggetti

E’ fondamentale sapere che la variabile oggetto (G) non contiene
l’oggetto, ma un riferimento ad esso:



G si riferisce all’oggetto Giocatore creato con l’operazione new
Quindi se creiamo un’altra variabile di tipo Giocatore G1 e copiamo
G in G1, non abbiamo due oggetti distinti, ma due riferimenti distinti
allo stesso oggetto
Giocatore G1=G;
Ogni operazione fatta su G1, influirà anche sull’oggetto G:
G.nome equivale a G1.nome e viceversa
Riferimenti agli oggetti
G
G1
Giocatore
Nome
Leonardo
Cog
Rigutini
Carte Iniz.
Carte rich.
Definire una classe
Classi

Come detto, con il termine di classe si intende la descrizione
astratta di una classe di oggetti:


Le variabili e le funzioni membro specificate nella classe sono quelle che
poi potranno essere invocate utilizzando l’oggetto
Ma come si definisce una classe?
Ogni linguaggio di programmazione fornisce i suoi costrutti per
definire una classe. Nel JAVA si usa la parola riservata class :
class prova {
variabili membro
costruttori
funzioni membro
}
Classi

Una classe deve poter essere utilizzata in qualunque parte del
progetto, ovvero deve essere public (pubblica):

Nella dichiarazione della classe la parole public o private
specificano il campo di visibilità della classe


una classe public è visibile ed utilizzabile da tutti
una classe private è invece utilizzabile solamente all’interno del file in
cui è definita. Molte volte infatti in uno stesso file possono essere definite
più di una classe, l’importante è che se si vuole rendere utilizzabile una
di esse deve essere public ed avere il nome del file
public class prova {
variabili membro
costruttori
funzioni membro
}
Definire una classe

Quando progettiamo una classe, noi decidiamo quali metodi e quali
variabili essa contiene:


Le variabili e le funzioni definite in una classe saranno poi utilizzate
dall’esterno della classe dal programmatore (con le debite limitazioni)
Questo modo di pensare al design di una classe come ad un
processo di creazione di “elementi” visibili dal programmatore, ci
porta a vedere le variabili e i metodi di una classe come una
interfaccia della classe:


Cioè possiamo pensare all’oggetto come ad una scatola nera di cui noi
vediamo solamente l’interfaccia
Inoltre possiamo anche non interessarci a come tale interfaccia è stata
implementata
Progettare l’interfaccia

Quindi per definire una classe è opportuno prima pensare
all’interfaccia della classe, cioè a cosa quella classe deve “mostrare”
al mondo esterno:


Giocatore  nome, cognome, ecc
E’ possibile definire dei metodi e delle variabili di una classe non
visibili all’esterno e quindi utilizzabili solamente dall’interno della
classe:

Tali elementi non “faranno parte dell’interfaccia della classe” ma
serviranno alla classe stessa per realizzare operazioni interne
Membri public e private

Quando progettiamo una classe è necessario individuare ciò che
sarà possibile utilizzare e cosa invece è solamente necessario al
corretto funzionamento della classe:


Nel secondo caso, diventa pericoloso permettere che altre classi
possano modificare variabili o utilizzare funzioni pensate per lavorare
sullo stato interno della classe stessa
Esistono perciò due tipi di elementi membro di una classe:


public, la cui visibilità è totale: le variabili così sono leggibili e
modificabili e le funzioni sono invocabili da chiunque;
private, la cui visibilità è ristretta alla classe proprietaria. T
Membri public e private

Una volta dichiarati i membri di una classe, è possibile accedere ad
essi utilizzando il carattere “.”:
[Nome_Oggetto].[Nome_Membro]

Ovviamente cercare di accedere ad un membro private da fuori
della classe, il compilatore ritorna errore
Variabili membro
Dichiarare le variabili della classe


Una volta “aperta” la definizione di una classe, è possibile dichiarare
le variabili membro della classe
Tale dichiarazione avviene con una semplice istruzione di
dichiarazione di variabile:
public class prova {
public int a;
private double b;
Car auto;
…
}

In tale forma le variabili non sono inizializzate e sarà necessario
farlo o nel costruttore oppure nel codice di qualche metodo,
comunque prima che vengano utilizzate
Dichiarare le variabili membro della classe

E’ possibile però utilizzare la forma di dichiarazione delle variabili
con inizializzazione immediata:
public class prova {
public int x=3;
private double b=2.3;
…
}

Tale inizializzazione ha il risultato di inizializzare le variabili ai valori
prescelti a tempo di costruzione, ossia come se tale inizializzazione
fosse fatta nel costruttore
Costanti

Normalmente è utile definire all’interno di una classe delle costanti:


Es. n° di desideri esprimibili con la classe “lampada di Aladino”, numero
di porte della classe “Car”, ecc…
Una costante viene definita aggiungendo la parola riservata final
alla dichiarazione della variabile:
final int nDesideri=3;
final int nPorte=4;

Il valore di una variabile definita come final non può più essere
modificato
Costanti

Ovviamente, essendo una dichiarazione di costante, la
dichiarazione richiede l’inizializzazione della variabile
Normalmente si utilizzano nomi tutti scritti in maiuscolo per le
costanti:
final int NDESIDERI=3;
final int NPORTE=4;


Le costanti possono essere definite private o public :

L’accesso alle costanti è eseguito tramite il punto come un normale
accesso alle variabili membro
Costanti

Dichiarazione:
Visibile solamente alla classe di appartenenza
private final int NPORTE=4;
Visibile da tutte le classi
public final int NPORTE=4;

Accesso alla variabile:
final Car auto= new Car();
int y=auto.NPORTE;
auto = new Car();
Non ammessa
Riferimento costante, l’oggetto è modificabile
y memorizza il valore di
NPORTE dell’oggetto auto
di tipo Car  solo se
NPORTE è dichiarato
public nella classe Car
Metodi
Dichiarare i metodi di una classe

Oltre alle variabili membro, è possibile specificare funzioni membro
per una classe

La dichiarazione di una funzione membro è del tutto simile ad una
dichiarazione di funzione normale:
public/private [tipo_di_dato_restituito] [nome_funzione]([lista_parametri])

Il JAVA prevede di implementare la classe in fase di dichiarazione
quindi alla sintassi qui sopra seguirà immediatamente il blocco di
implementazione:
public/private [tipo_di_dato_restituito] [nome_funzione]([lista_parametri]) {
Lista istruzioni;
}
Es.
public class Rectangle {
/** Variabili membro : coordinate del vertice alto a sx*/
private int x;
private int y;
/**
* Funzione membro : sposta il rect di dx e dy
* @param dx
* @param dy
*/
public void translate(int x, int y) {
this.x=this.x+x;
this.y=this.y+y;
}
}
Parametri

I metodi di una classe sono semplicemente “normali” funzioni
assegnate ad una classe. Come tali, i metodi utilizzano i
parametri per “comunicare” con l’esterno

Il JAVA non prevede la possibilità di dichiarare valori di default
per i parametri

Inoltre, dato che ogni variabile oggetto contiene i riferimenti
all’oggetto piuttosto che l’oggetto stesso, il passaggio dei
parametri sebbene in realtà sia per copia, realizza un passaggio
per riferimento:

infatti quello che viene copiato è il riferimento all’oggetto
Parametri


I parametri sono variabili locali alla funzione e spariscono una volta
terminata l’esecuzione del metodo
All’interno della funzione è possibile comunque modificare il
contenuto delle variabili parametro, ricordando sempre che stiamo
modificando un riferimento ad un oggetto
Variabili locali

All’interno di un metodo è possibile definire ed utilizzare nuove
variabili:


Queste variabili hanno scope locale alla funzione e spariscono una volta
terminata la chiamata al metodo
Il JAVA permette di dichiarare variabili locali con lo stesso nome
delle variabili membro della classe:


In questo caso le variabili membro della classe sono messe in ombra
dalle nuove variabili, nel senso che ogni accesso è riferito alla variabile
locale.
L’accesso alla variabile membro invece che alla variabile locale viene
risolto tramite l’uso del parametro implicito this
Parametro implicito this


Dall’interno di un metodo è possibile accedere implicitamente alle
variabili e metodi della classe di cui fa parte la funzione stessa. Nel
caso però che una variabile locale “copra” una variabile globale
della classe, è necessario poter distinguere
La risoluzione in questo caso viene fatta utilizzando il parametro
implicito this


In ogni funzione oltre ai parametri passati tramite prototipo, esiste
sempre una variabile che fa riferimento alla classe stessa
Utilizzando tale parametro è possibile disambiguare una variabile locale
con lo stesso nome di una globale
Overloading

Normalmente capita di dover dichiarare più funzioni con lo stesso
nome e con la stessa funzionalità che differiscono solamente dal
numero o dal tipo dei parametri in ingresso

In questi casi si parla di overloading, cioè sovraccarico del metodo

Il metodo giusto infatti viene risolto


dal compilatore (a tempo di compilazione quindi) nel caso sia possibile
farlo  linking statico
dalla JVM (a tempo di escuzione) nel caso non sia possibile stabilire in
compilazione il tipo di oggetto (vedremo più avanti nei casi di interfaccia
ed ereditarietà)  linking dinamico
Costruttore
Costruttore

Quando un oggetto è istanziato, si dice che viene costruito

Il processo di costruzione avviene nel seguente modo:


Il compilatore quando trova la parola riservata new invoca
automaticamente un metodo particolare dell’oggetto, il costruttore
Tale metodo è definito secondo alcune regole ben precise:



è un membro public
ha lo stesso nome della classe
non restituisce alcun valore (void)
Es.
public class Rectangle {
/** Variabili membro : posizione vetice alto a sx */
private int x;
private int y;
/** Costruttore : inizializza il rect in (x,y)=(0,0) **/
public Rectangle() {
}
/**
* Funzione membro : sposta il rect dx e dy
* @param dx
* @param dy
*/
public void translate( int dx, int dy) {
x=x+dx;
y=y+dy;
}
Costruttore con parametri

Quando costruiamo un oggetto possiamo aver bisogno di passare
dei parametri per la costruzione (parametri di costruzioni visti in
precedenza):

in questo caso nella definizione del costruttore è necessario specificare
la lista di parametri
Es.
public class Rectangle {
/** Variabili membro : coordinate del vertice in alto a sx */
private int x;
private int y;
/** Costruttore : inizializza il rect in (0,0) **/
public Rectangle() {
x=0;
y=0;
}
/** Costruttore con parametri: inizalizza il rect in (x,y) */
public Rectangle(int x,int y) {
this.x=x;
this.y=y;
}
Costruttore di default

Nel caso non venga esplicitamente fornito dal programmatore, il
compilatore utilizza un costruttore di default


Il costruttore di default non ha alcun parametro di costruzione:


Il costruttore infatti deve esistere comunque in una classe a prescindere
della esplicita volontà del progettista
Eventuali variabili nell’oggetto non inizializzate, rimangono tali fino ad
una necessaria inizializzazione esplicita successiva
NB: se viene definito anche un solo costruttore, allora il costruttore
di default non viene costruito.
Costruttore di copia

Molte volte può essere necessario creare un oggetto copia di
un altro oggetto della stessa classe. Questo implica definire un
costruttore che inizializza l’oggetto copiando lo stato dell’oggetto
passato come parametro

costruttore di copia
Es.
public class Rectangle {
/** Variabili membro : coordinate del vertice in alto a sx */
private int x;
private int y;
/** Costruttore : inizializza il rect in a (0,0) **/
public void Rectangle() {
x=0;
y=0;
}
/** Costruttore con parametri: inizalizza il Rect in (x,y) */
public void Rectangle(int x, int y) {
this.x=x;
this.y=y;
}
/** Costruttore di copia: inizalizza il Rect
* copiando il valore dell’oggetto B */
public void Rectangle(Rectangle R1) {
x=R1.x;
y=R1.y;
}
Costruttore di copia

Interessante far notare come il costruttore di copia permette di effettuare il
passaggio per valore di un oggetto ad una variabile:

Se infatti creiamo un oggetto di tipo Rectangle R1 inizializzato in un certo modo e
definiamo una variabile R2 anch’essa di tipo Rectangle che prende R1, ogni
operazione su R2 si riflette su R1 (e viceversa)
Rectangle R1= new Rectangle(5,10,20,30);
Rectangle R2=R1;
R2.translate(15,25);

Se però inizializziamo R2 con il costruttore di copia con R1 come parametro di
costruzione otteniamo per R2 un oggetto differente ed ogni operazione su di esso
non si riflette su R1 (e viceversa)
Rectangle R1= new Rectangle(5,10,20,30);
Rectangle R2= new Rectangle(R1);
R2.translate(15,25);
Costruttore di copia
public class Tassista {
/** Variabili membro : auto */
private Car x;
/** Costruttore : inizializza il tassista **/
public void Tassista() {
x=new Car();
}
/** Costruttore con parametri: assegna la macchina al Tassista */
public void Tassista(Car x) {
this.x=x;
}
/** Costruttore di copia: inizializza il tassista*/
public void Tassista (Tassista T1) {
x=R1.x;
}
Costruttore di copia

Attenzione: anche nel costruttore di copia, se copiamo oggetti
invece che tipi di dato primitivi, avremo due oggetti distinti cha
hanno come variabile membro uno stesso oggetto
Car
tassista
T1
x
tassista
T2
x
Overloading

Quando forniamo più costruttori ad una classe si parla di
overloading (sovraccarico) del costruttore:

Il costruttore di default è quindi sempre sovraccaricato non appena
viene fornito un costruttore
Nuova istanza

NB. I costruttori non sono “normali” funzioni membro della
classe e non possono essere invocati esplicitamente su un
oggetto esistente:
Car A = new Car();
…
A.Car();

Errore
Se vogliamo associare una nuova istanza ad una variabile oggetto è
necessario riutilizzare l’operatore new :
Car A = new Car();
…
A = new Car();
La variabile oggetto cambia il suo contenuto, ossia
l’indirizzo di memoria riferito. In questo caso l’oggetto
precedente non è più riferibile (a meno che non
esistano altri riferimenti attivi!)
Esempio

Progettiamo una classe BankAccount:
public class BankAccount {
variabili;
costruttori;
metodi;
}

Innanzitutto individuiamo l’interfaccia della classe:



Deposito denaro
Prelievo denaro
Saldo
Per ora fermiamoci qui
Esempio

La classe BankAccount necessita di una variabile membro che
memorizzi lo stato del conto corrente. Supponiamo di avere un
conto bancario senza tassi di interesse, date di invio resoconti ecc
… e di avere bisogno quindi solamente della cifra nel conto:
public class BankAccount {
private double balance;
costruttori;
metodi;
}

NB. La variabile membro è stata dichiarata private. Questa
informazione infatti è privata della classe ed ogni accesso ad essa è
permesso solamente tramite le funzioni esportate
Esempio

Creiamo il costruttore per la classe BankAccount:

In costruzione, l’unica operazione richiesta è quella di inizializzare la
variabile membro balance a 0. Tale operazione non richiede alcun parametro
di costruzione.
public class BankAccount {
/**
* Contenuto del conto
*/
private double balance;
/**
* Costruttore senza parametri
*/
public BankAccount() {
balance=0;
}
metodi;
}
Esempio

Potrebbe essere necessario aprire un conto inserendo
direttamente all’apertura un po’ di denaro: questa affermazione
si traduce con un costruttore con un parametro di costruzione.
/**
* Costruttore 2
* @param initBalance il saldo iniziale
*/
public BankAccount(double initBalance) {
balance= initBalance;
}
Esempio

Infine implementiamo le tre funzioni individuate come interfaccia per
la class BankAccount

Deposito:
/**
* Versa denaro nel conto
* @param amount importo da versare
*/
public void deposit(double amount) {
balance= balance+amount;
}
Esempio

Prelievo:
/**
* Ritira denaro dal conto
* @param amount importo da versare
*/
public void withdraw(double amount) {
balance= balance-amount;
}
Esempio

Saldo:
/**
* Ritorna il saldo del conto
* @return saldo attuale
*/
public double getBalance() {
return balance;
}
Esempio

Per testare la nostra prima classe creiamo una classe di test:
testBankAccount
public class testBankAccount {
public static void main(String[] args) {
BankAccount LChecking = new BankAccount();
LChecking.deposit(2000);
LChecking. withdraw(500);
System.out.println(LChecking.getBalance());
}
}
Metodi static
Metodi static

Ogni volta che definiamo la funzione main, notiamo la presenza
nella dichiarazione della parola static, ma cosa vuol dire?

Può essere necessario definire delle funzioni membro che possano
essere chiamate senza che l’oggetto sia istanziato:


Se voglio calcolare il logaritmo di un numero, è preferibile non dover
istanziare ogni volta un oggetto di tipo logaritmo e poi chiamare la
funzione calcola(double x)
Le funzioni static sono funzioni che possono essere invocate senza
che l’oggetto sia istanziato, facendo riferimento solamente alla
classe che le definisce:

Es.
double r=Matematica.log(double x);
Metodi static

La funzione main, per definizione deve poter essere invocata
quando ancora l’oggetto non esiste, altrimenti l’oggetto dovrebbe
essere istanziato nel corpo di una qualche altra funzione main, che
però affinchè sia eseguibile dovrebbe essere invocata senza dover
a sua volta istanziare l’oggetto altrimenti si andrebbe avanti
all’infinito:


Ecco perché la funzione main è sempre una funzione static
Da notare che una funzione static non può accedere a variabili
o funzioni “non static” della classe, poiché al momento della
sua esecuzione l’oggetto non è istanziato e le variabili o
funzioni “non static” non esistono
Metodi static

Le funzioni static realizzano quelle che nella programmazione
procedurale erano le funzioni (o procedure) globali, invocabili in
qualunque parte del programma senza essere legate ad alcun
oggetto

Vedremo più avanti cosa significa static per una variabile membro
Esempio
Come esempio di metodo static proviamo a creare la classe
matematica:
public class matematica {
// calcola il fattoriale di n
static public int fatt(int n) {
if (n==0) return 1;
else return n * matematica.fatt(n-1);
}
// calcola la somma dei primi n numeri interi
static public int sum(int n) {
return (n*(n+1))/2;
}

}
Esempio

Creiamo una classe di test per matematica: mateTest
public class mateTest {
// test per le funzioni static sum e fatt
public static void main(String[] args) {
int x=5;
System.out.println(matematica.sum(5));
System.out.println(matematica.fatt(5));
}
}
Variabili static
Variabili static

Definire una variabile static significa fare in modo che l’istanza di
tale variabile sia condivisa tra tutte le istanze degli oggetti di quella
classe

Il che vuol dire che la prima creazione di un oggetto di quel tipo crea
la variabile in questione; tutte le successive istanze di nuovi oggetti
di quel tipo, non inizializzano quella variabile membro ma faranno
riferimento alla variabile membro dell’oggetto creato per primo

Le variabili membro static realizzano in un certo modo le variabili
definite globali nei linguaggi procedurali:

Un uso comune è utilizzare variabili membro static per realizzare
contatori di istanze di una classe
Inizializzazione di variabili static

Le variabili static non possono però essere inizializzate
all’interno del costruttore:



Questo perché altrimenti verrebbero comunque modificate e
reinizializzate alla costruzione di ogni oggetto
E’ necessario quindi inserire l’inizializzazione direttamente nella
definizione della variabile nella classe:
static int count=0;
Un modo poco utilizzato è quello di inserire un blocco di
inizializzazione di tipo static:
private static int counter;
static {
counter=0;
}
Costanti statiche

Le costanti, viste come variabili particolari, possono essere
anch’esse dichiarate static

Questo significa che la della costante esiste solamente una
istanza per tutti gli oggetti della classe
Es.
static private final int NPORTE=4;

Visibile solamente alla classe di
appartenenza. La costante è
condivisa tra tutti gli oggetti
della classe
static public final int NPORTE=4;
Visibile da tutte le classi. La
costante è condivisa tra tutti gli
oggetti della classe
Costruttori privati


Avevamo detto che i costruttori “devono” essere dichiarati public altrimenti
non sono utilizzabili.
In realtà possono anche essere dichiarati costruttori privati che possono
quindi essere invocati solamente dall’oggetto stesso:


Così sembra una contraddizione dato che per invocare il costruttore è necessario
avere l’oggetto ma per avere l’oggetto è necessario poter invocare il costruttore
In realtà tale situazione viene risolta utilizzando un metodo static che
ritorna un oggetto dello stesso tipo (quindi come se fosse invocato un
costruttore pubblico) ma creato in una funzione membro dell’oggetto
(utilizzando quindi il costruttore privato):

Questa situazione permette per esempio di limitare il numero di oggetti di quella
classe che possono essere costruiti, utilizzando un contatore ed incrementando
quest’ultimo di uno alla creazione di un oggetto (costruzione controllata)
Scarica

2. classi ed oggetti