Newsgroup: it.comp.java
Titolo: costruttore e distruttore

public class pippo {
    // costruttore, o perlomeno io lo ho sempre chiamato cosi!
    public pippo() {
    }
}
come esiste un costruttore, esiste un distruttore : metodo che viene
chiamato dalla VM o garbage collector come mi sembra ci sia in c++ :
public class pippo {
    public ~pippo() {
    }
}
Grazie.

protected void finalize()
          Called by the garbage collector on an object when garbage collection
determines that there are no more references to the object.

--------------------------------
Inviato via 
http://usenet.libero.it



Non capisco dove sia la domanda, comunque cerchiamo di non confondere le
idee. Il distruttore in C++ viene richiamato in condizioni ben precise e
controllabili: uscita di un puntatore dallo scope (per oggetti allocati
sullo stack) o esplicita deallocazione con delete (per quelli allocati
nell'heap).
In Java il concetto di deallocazione esplicita non esiste, per questo ti
devi affidare al garbage collector. Ora vorrei evitare discussioni trite e
ritrite su come funzioni il gc (se ne č parlato fino alla nausea, e la
documentazione č abbastanza chiara di per sč). Sappi comunque che non puoi
considerare il metodo finalize come un distruttore C++.
Se ti serve un distruttore, vale a dire un metodo che "rimetta le cose a
posto" quando sei sicuro di non dover piů utilizzare un oggetto, la
procedura di solito č questa:
1) Crei un tuo metodo che faccia pulizia all'interno dell'oggetto (come
chiudere file, svuotare buffer, chiudere connessioni socket o DB,
trasmettere ad altri oggetti/processi un evento di "fine lavori" ecc....)
2) all'esterno assicurati di impostare a null tutti i riferimenti
all'oggetto che hai finito di utilizzare: questo č l'unico metodo per
suggerire al GC quali oggetti puň buttare via
3) [opzionale] richiami esplicitamente System.gc();
-- 
"tanto va la gatta al largo che affoga"
(per rispondere personalmente leva IlDitoDalCulo)

...

Grazie dell'esaustiva risposta.
Ho fatto un metodo per "pulire" il tutto ma dato che io stesso
commettevo l'errore di fare ogg = new oggetto(); riallocado dati proma
di aver fatto
ogg.pulisci(); mi chiedevo una seconda persono meno esperta di me nel
mio gruppo di lavoro se avesse potuto commettere tale errore, o altri
piu' evidenti. in questo modo cercavo una via piu' facile e sicura di
pulizzia. Cmq ho deciso di usare io in prima persona la proprieta'
ogg.pulisci(); ed in piu' con uno switch pulire al protected void
finalize().
Tu che ne pensi e' una stupidaggine o potrebbe essere utile in caso di
dimenticanze mie o di altri?


 
Mi sembra perfettamente corretto, potrebbe risparmiare diversi memory leaks
anche nel caso in cui le tue classi siano utilizzate in modo errato.
Comunque se prevedi dei metodi di pulizia esplicita pre-deallocazione
faresti meglio a specificarso chiaramente nella documentazione.
In questo modo hai un motivo in più per *incoraggiare* i meno esperti a
spendere qualche minuto in più per leggere il "bugiardino" ;)


 finalize().
Fermi tutti.... guarda che non ha senso chiamare direttamente finalize().
finalize() viene chiamato dalla VM prima di deallocare l'oggetto. In poche
parole se l'oggetto è totalmente dereferenziato viene finalizzato e al
thread sucessivo del GC viene "mangiato".
Se chiami direttamente il finalize ottieni di referenziare l'oggetto e
quindi di renderlo non "mangiabile". 
E' sbagliato mettere codice di pulizia nel finalize perche non hai nessuna
certezza ne sul se e neanche sul quando l'oggetto viene deallocato dal GC e
quini eseguito il finalize.
In poche parole se ad esempio l'oggetto apre una connessione ad un DB e tu
chiudi la connessione nel finalize puo' capitare che non venga MAI chiusa.
Anche la chiamata esplicita al GC non serve a nulla. Il GC è malmostoso, se
non è il suo momento non interviene.
Il codice di pulizia va messo in un blocco try { } finally {}, il blocco
finally viene sempre eseguito a meno di disastri immani, al che non ti devi
preoccupare piu' della pulizia.
Ciao
Luca

 Luca
Veramente avevo capito che stefano intendesse una cosa del genere:
--------------------------------------
public class ClasseComplicata {
  private boolean isclean;
  //altri dati privati
  public ClasseComplicata() {
    isclean=false;
    //tutte le altre inizializzazioni
  }
  //i metodi della classe
  public void clean() {
    //tutte le deinizializzazioni (close/flush/broadcast ecc...)
    //Logicamente tutte le eccezioni devono essere catturate
    //e gestite senza rilanciarle. Il perchè sarà comprensibile
    //tra poco...
    isclean=true;
  }
  protected void finalize() {
    if (!isclean) clean();
  }
}
----------------------------------
Secondo me è l'ideale per classi complesse...


[Ech3L0n] NSA wrote:

Yup, è sicuramente l'approccio migliore quando bisogna rilasciare delle 
risorse; va da se che il metodo di terminazione esplicita(clean()) deve 
essere chiamato dall'utilizzatore(finalize fa da paracadute :), 
preferibilmente in un try finally, cosi da essere sicuri, eccezioni o 
no, che il metodo di terminazione viene eseguito.
ClasseComplicata cc = new ClasseComplicata();
try {
   // Usa ClasseComplicata
   ...
} finally {
   cc.clean();
}
Marco
-- 
replay: remove .duh.spam

Grazie a tutti della risposta e' cosi che intendevo ed adottero' senza
dubbio questo metodo :
public class ClasseComplicata {
  private boolean isclean;
  //altri dati privati
  public ClasseComplicata() {
    isclean=false;
    //tutte le altre inizializzazioni
  }
  //i metodi della classe
  public void clean() {
    //tutte le deinizializzazioni (close/flush/broadcast ecc...)
    //Logicamente tutte le eccezioni devono essere catturate
    //e gestite senza rilanciarle. Il perchè sarà comprensibile
    //tra poco...
    isclean=true;
  }
  protected void finalize() {
    if (!isclean) clean();
  }
}
ciao !