2013-01-23 9 views
13

Czy są jakieś szczegóły dotyczące czyszczenia obiektu przy użyciu finalize(), jeśli konstruktor obiektu jest wyjątkiem.Czy sfinalizowanie może zostać wywołane po tym, jak konstruktor zgłasza wyjątek?

Gdy ta metoda jest wywoływana, jest notorycznie źle zdefiniowana. Zgodnie z instrukcją:

Język programowania Java nie gwarantuje, który wątek będzie wywoływał metodę finalizacji dla dowolnego obiektu. Gwarantuje to jednak, że wątek wywołujący sfinalizowanie nie będzie blokował żadnych widocznych blokad synchronizacji użytkownika po wywołaniu finalizacji. Jeśli wyjątek nieprzechwycony zostanie odrzucony przez metodę finalizacji, wyjątek zostanie zignorowany i zakończona zostanie finalizacja tego obiektu.

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

Nie byłem w stanie wywołać metodę sfinalizować w ten sposób. Czy ktokolwiek wie, czy to nie jest GARANTEDED lub jeśli jest w niektórych przypadkach wywoływana po tym, jak konstruktor nie zainicjował obiektu (thew wyjątek).

Pytam o to, ponieważ mam obiekt, którego nie należy czyścić dwukrotnie. Próbuję zrozumieć, czy można bezpiecznie wyczyścić przed wyrzuceniem wyjątku, czy też muszę zostawić znacznik dla finalize(), aby skutecznie pominąć i nic nie robić.

+3

+1 Podejrzewam, że jest to coś trzeba będzie sprawdzić, jak różne JVM może zachowywać się inaczej. –

+0

Użycie 'finalize' jest złe. –

+1

@Peter JLS jest dość szczegółowy, obiekt jest finalizowany, gdy konstruktor obiektu [base] zakończy się pomyślnie. –

Odpowiedz

10

Moje badanie pokazuje, że może

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); 
    } 
} 

drukuje

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

jest na Java HostSpot Client VM 1.7.0_03

+0

To bardzo pomocne! Czy mógłbyś edytować odpowiedź, której JVM próbowałaś, a ja ją zaakceptuję. Wielkie dzięki! –

+0

jest tak, ponieważ domniemana super() nie rzuciła wyjątku. –

7

Według sekcji 12.6.1. Implementing Finalization z JLS:

Obiekt o jest nie można go sfinalizować, dopóki jego konstruktor nie wywoła konstruktora obiektu o, i że wywołanie zakończyło się pomyślnie (to znaczy bez odrzucenia wyjątku).

Jeśli konstruktor zgłasza wyjątek po zakończeniu konstruktora obiektu, wówczas obiekt powinien być finalizable, więc finalize() nadal może być nazywany.

Istnieje dobry przykład przechodzenia przez budowę obiektu w sekcji 12.5. Creation of New Class Instances, która pokazuje dokładnie, kiedy wywoływany jest obiekt Konstruktor.

+0

Oznacza to, że w klasie X X() {super();} wywołanie super() do obiektu zostało wykonane bez wyjątku. Klasa Object ma kod kleju do rejestracji alokacji sterty, przydzielonej przez nowy, do usuwania śmieci. –

1

Aby zademonstrować jaśniej:

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); 
    } 
} 

drukuje

java.lang.RuntimeException 
    at test.Test1.<init>(Test1.java:13) 
    at test.Test1.main(Test1.java:24) 
[email protected] 
finalized 
Powiązane problemy