2009-09-04 14 views
13

Non abbiamo alcun distruttore in Java come abbiamo in C++.Qual è il modo migliore per ripulire un oggetto in Java?

Q1. Come dobbiamo pulire qualsiasi oggetto in java.

Q2. Esiste un'alternativa a un blocco finale.

Q3. A volte dobbiamo chiamare l'inizializzazione/terminazione esplicita di un codice di terze parti dalla nostra classe, ad es.

public classs MyClass{ 
    public MyClass(){ 
     ThirdPartyInitialize(); 
    } 

    protected void finalize(){ 
     ThirdPartyTerminate(); 
    } 
} 

È questo il modo corretto?

risposta

12

Generalmente non è possibile "ripulire" gli oggetti Java da soli. Il garbage collector decide quando pulire gli oggetti. È possibile indicare quando si è terminato con un riferimento a un oggetto impostandolo su null, ma in genere è sufficiente lasciarlo uscire dall'ambito. Ad ogni modo, non hai ancora il controllo su quando viene raccolta la spazzatura.

Il blocco finally è inteso per l'esecuzione di azioni sia che un'eccezione sia generata da un blocco try oppure no, ed è il posto migliore per eseguire la pulizia. In generale si eliminano solo le risorse non object come gli open stream.

finalize() non è garantito per essere chiamato perché il garbage collector non è garantito per essere chiamato prima che il programma venga chiuso. Non è proprio come un distruttore C++ perché i distruttori C++ vengono sempre chiamati e puoi fare affidamento sul fatto che vengano chiamati. Non è possibile fare affidamento su finalize().

Quindi 1) utilizzare finally blocchi per liberare risorse non oggetto 2) lasciare che il garbage collector ripulire oggettuali risorse 3) si può suggerire per il garbage collector che si è fatto con un oggetto impostandolo su null se è usato in un metodo a lunga corsa.

0

Il finalize viene utilizzato in modo analogo a un distruttore, ma, se si utilizza il try ... finally block for resources, è possibile aprire una risorsa e infine bloccare la chiusura della risorsa.

Il blocco finally viene sempre chiamato, quando il blocco viene chiuso, normalmente o tramite un'eccezione generata.

La finalizzazione è rischiosa per la gestione delle risorse, in quanto non si sa quando verrà chiamato, e se si chiude un oggetto che è stato finalizzato, potrebbe richiedere del tempo.

Il blocco finale è l'approccio migliore.

+0

avrei * non * dire che finalize() è simile a un distruttore. Il resto del tuo testo va bene, ma in gran parte contraddice quella prima affermazione. Non si sa mai quando finalize() verrà chiamato. Quindi è diverso da un distruttore C++, che viene chiamato quando un oggetto lascia scope o viene cancellato. –

+0

Quando un oggetto viene sottoposto a garbage collection, viene chiamato il finalizzatore, ma non ha idea di quando verrà raccolto del garbage, quindi il finalizzatore potrebbe non essere chiamato in modo tempestivo. –

5

Si potrebbe anche aggiungere un shutdown hook al programma, se il programma è in fase di arresto troppo:

//add shutdown hook 
Runtime.getRuntime().addShutdownHook(new Thread() { 
    public void run() { 
     ThirdPartyTerminate(); 
    } 
}); 
1

A1. Se è necessario inizializzare l'inizializzazione di un oggetto, quindi Dispose pattern is the way to go.

A2. Dal punto di vista della gestione delle risorse, non c'è. Va notato tuttavia che un blocco finale non è una gestione delle risorse deterministica.

A3. Sì, è il modo corretto.

2

Il modo migliore per ripulire gli oggetti è far cadere l'oggetto.

Infine i blocchi possono essere astratti utilizzando l'idioma di Execute Around.

I finalizzatori devono essere evitati. Probabilmente non verranno chiamati immediatamente. La pulizia dovrebbe avvenire comunque. Sono relativamente lenti. Si potrebbe voler aggiungere uno come rete di sicurezza se si sta scrivendo un wrapper di risorse di basso livello (per esempio un handle di file) se le prestazioni non sono critiche.

+0

Esiste qualche relazione tra prestazioni e infine blocco? – pankajt

+0

Non sono sicuro di cosa intendi. Se non si rilascia immediatamente la risorsa, si hanno potenziali problemi (e non solo prestazioni). Se non si sta generando un'eccezione, allora su qualsiasi applicazione ragionevolmente eccezionale non fa alcuna differenza se esiste un blocco try o no (questo è diverso dalla maggior parte delle implementazioni C++). Se il contenuto del blocco finally è lento, potrebbe valere la pena di tornare a un pool (anche se il "pool" rilascia appena la risorsa in un thread separato). –

1

È possibile ripulire gli oggetti rimuovendo i riferimenti ad esso, quando non sono più necessari. Non devi farlo esplicitamente. Una pulizia esplicita richiederebbe l'impostazione del riferimento su null, fornendo quindi un suggerimento al garbage collector che l'oggetto può essere raccolto. Questo suggerimento funziona a causa dei conteggi dei riferimenti interni per ciascun oggetto, che vengono mantenuti internamente. Per esempio


C a = new C(); //create an object of class C and assign it to 'a' 
a = new C(); //create another object of class C and assign it to 'a'. The older object is no longer referred to. It is now eligible for GC. 

ci sono alternative migliori per finalizzare() a seconda di quanto finalizzare() sta aiutando la vostra situazione.

Spesso, la migliore pratica consiste nel fornire un metodo come close() o disposeResources() nell'API che consenta al chiamante di aiutare l'API a ripulirsi. Ad esempio, lo java.sql.Connection class does this. Questo è migliore del metodo finalize(), poiché la JVM chiamerà il metodo finalize(). Spesso il metodo finalize() viene eseguito da un thread a bassa priorità nella JVM, causando alcuni errori strani.

Nel caso della classe Connection, attendere che JVM esegua la finalizzazione risulta costoso in molte applicazioni, poiché un database può accettare solo così tante connessioni alla volta. Pertanto, la maggior parte dei programmatori chiamerà close() esplicitamente su un oggetto Connection.

Nel tuo caso, si deve tradurre in qualcosa di simile (e, in questo contesto, il blocco finally è garantito per funzionare sempre)


try 
{ 
ThirdPartyInitialize(); 
// use third party component in this try block 
} 
finally 
{ 
ThirdPartyTerminate(); 
} 

Questo è simile al modo in cui il classe Connection è utilizzato anche in più situazioni.

-1

Gli oggetti Java non devono mai essere "ripuliti", GC funziona solo. Quasi ogni volta che ho visto someObject = null nel codice, è stato qualcuno che non sapeva cosa stavano facendo. C'è un caso teorico per questo, ma è davvero un caso limite e generalmente meglio gestito in altri modi, come il tentativo recentemente aggiunto con la risorsa.

Se si dispone di una risorsa esterna che deve essere ripulita quando un oggetto non è più utilizzato, è un'altra questione.

Ci sono classi "di riferimento" che terranno un tipo speciale di riferimento alla classe - non fermerà la garbage collection, ma può notificare quando la classe è raccolta dati inutili (tramite una richiamata se lo si desidera). Cerca WeakReference, PhantomReference, ecc.

Questi sono affidabili e funzionano in modo molto più deterministico di un vero metodo di "finalizzazione" perché la richiamata è al di fuori della classe, quindi non si finisce per eseguire un metodo in alcuni file cancellati o cancellati stato e i problemi che potrebbero causare.

+0

Questa non è una risposta alla domanda di cui sopra dato che stai essenzialmente dicendo loro di non ripulire i loro oggetti. Esistono molte istanze (specialmente quando si utilizza un bus eventi e variabili di thread) in cui gli oggetti devono essere ripuliti e non registrati per questi tipi di sistemi. Se stai usando pojos molto semplici, allora sì non hai bisogno di fare molto. Tuttavia, qualsiasi attività da remoto complessa deve essere valutata per gli oggetti che perdono come la principale causa di problemi nella comunità così com'è oggi. – dsutherland

+0

In realtà, una grande quantità di oggetti java richiedono di chiamare su di essi un metodo di pulizia. 'Obj.open (...); Obj.close(); ' – iPherian

1

Due opzioni di zucchero sintassi:

1) v'è un'annotazione @Cleanup a Lombok che maggiormente assomiglia C++ distruttori (more):

@Cleanup 
ResourceClass resource = new ResourceClass(); 

2) C'è anche try-with-resources economico. Per esempio:

try (BufferedReader br = new BufferedReader(new FileReader(path))) { 
    System.out.println(br.readLine()); 
} 
Problemi correlati