2013-01-23 15 views
13

Ci sono dettagli sul fatto che un oggetto venga pulito o meno usando finalize() se il costruttore di quell'oggetto presenta un'eccezione.Può essere chiamato dopo che un costruttore ha generato un'eccezione?

Quando questo metodo viene chiamato è notoriamente mal definito. In base al manuale:

Il linguaggio di programmazione Java non garantisce quale thread applicherà per un determinato oggetto. È garantito, , tuttavia, che il thread che richiama finalize non manterrà alcun blocco di sincronizzazione visibile all'utente quando viene richiamata la finalizzazione. Se un'eccezione non rilevata viene generata dal metodo finalize, l'eccezione è ignorata e la finalizzazione di tale oggetto termina.

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#finalize%28%29

non sono stato in grado di innescare il metodo Finalize in questo modo. Qualcuno sa se è possibile che NON venga chiamato o che in alcuni casi viene chiamato dopo che il costruttore non è riuscito a inizializzare l'oggetto (con un'eccezione).

Lo chiedo perché ho un oggetto che non deve essere ripulito due volte. Sto cercando di capire se è sicuro ripulire prima di lanciare l'eccezione o se devo lasciare un marcatore per finalize() per saltare in modo efficace e non fare nulla.

+3

+1 Ho il sospetto che è qualcosa che sarà necessario verificare a diverse JVM potrebbero comportarsi in modo diverso. –

+0

L'uso di 'finalize' è malvagio. –

+1

@Peter il JLS è abbastanza specifico, un oggetto è definibile una volta che il costruttore per l'oggetto [base] è stato completato con successo. –

risposta

10

Il mio test dimostra che può

public class Test1 { 

    Test1() { 
     throw new RuntimeException(); 
    } 

    @Override 
    protected void finalize() throws Throwable { 
     System.out.println("finalized"); 
    } 

    public static void main(String[] args) throws Exception { 
     try { 
      new Test1(); 
     } catch (RuntimeException e) { 
      e.printStackTrace(); 
     } 
     System.gc(); 
     Thread.sleep(1000); 
    } 
} 

stampe

java.lang.RuntimeException 
    at test.Test1.<init>(Test1.java:13) 
    at test.Test1.main(Test1.java:24) 
finalized 

è su Java HostSpot client VM 1.7.0_03

+0

Questo è molto utile! Potresti modificare la tua risposta su quale JVM hai provato e accetterò. Grazie molto! –

+0

perché il super implicito() non ha generato un'eccezione. –

7

Secondo la sezione 12.6.1. Implementing Finalization della JLS:

Un oggetto o è non è definibile fino a quando il suo costruttore non ha richiamato il costruttore per Object su o e l'invocazione è stata completata correttamente (cioè senza generare un'eccezione).

Se il vostro genera un'eccezione dopo completa la costruzione Object, quindi l'oggetto dovrebbe essere finalizable, così finalize() poteva ancora essere definito.

C'è un buon esempio di passaggio attraverso la costruzione di un oggetto nella sezione 12.5. Creation of New Class Instances che mostra esattamente quando viene chiamato il costruttore Object.

+0

Ciò significa che nella classe X X() {super();} la chiamata super() a Object è stata completata senza eccezioni. La classe Object ha il codice colla per registrare l'allocazione dell'heap, allocata da nuova, per la garbage collection. –

1

Per dimostrare più chiaramente:

public class Test1 { 

    public static class LifeBoat extends RuntimeException 
    { 
     private Test1 passenger; 
     public Test1 getPassenger(){return passenger;} 
     public LifeBoat(Test1 passenger){this.passenger=passenger;} 
    } 

    Test1() { 
     super(); //once this is finished, there is an Object to GC per JLS 12.6.1. 
     throw new LifeBoat(this); 
    } 

    @Override 
    protected void finalize() throws Throwable { 
     System.out.println("finalized"); 
    } 

    public static void main(String[] args) throws Exception { 
     try { 
      new Test1(); 
     } catch (LifeBoat e) { 
      Test1 obj; 
      obj=e.getPassenger(); 
      System.out.println(obj); 
     } 
     System.gc(); 
     Thread.sleep(1000); 
    } 
} 

stampe

java.lang.RuntimeException 
    at test.Test1.<init>(Test1.java:13) 
    at test.Test1.main(Test1.java:24) 
[email protected] 
finalized 
Problemi correlati