2017-06-05 65 views
4

所以我一直在經歷「Effective Java 2nd Ed。」終止一個對象是否與nulling相同?

在第7項中,他談到了不使用終結器,因爲它們會導致很多問題。

但不是使用終結器,我們可以「提供一個明確的終止方法」,這些的一個例子是close語句。我不明白什麼是「終止聲明,它們和終結器之間有什麼區別?」

我得出結論:終止一個對象就像是將它歸零,因此資源被釋放,但我想我不會明白很好。所以我感謝所有幫助的差異。

謝謝!

+2

取消對象不會釋放任何東西。 – assylias

+2

我想你跳過了解釋終結器用於清理非內存事物(例如打開連接,打開文件,其他系統資源)的部分。你需要做這些事情,否則你會有資源泄漏。 – RealSkeptic

回答

8

,但使用的終結,我們可以「提供一個明確的 終止法」和那些的一個例子是緊密的語句。

作者引用了一個close()方法,該方法提供了一種清理使用資源釋放對象的方法。

例如,當您創建和操縱InputStreamOutputStream,你不想依賴於Java終結(可能存在這些接口的一些子類。例如,它是爲FileInputStream類的情況下定義一個finalize()方法)來釋放與流關聯的資源,但是您想使用API​​提供的方法來完成它:void close(),因爲它更可靠作爲終結器。

java.sql.Statement作品以同樣的方式:它提供了close()方法來釋放相關的聲明實例JDBC資源。

我得出的結論是終止一個對象就像是將其歸零 因此資源被釋放。

指定一個對象到null不需要釋放所有應該釋放的資源。此外,如果對象或對象的字段仍然被另一個活動對象引用,則該對象將難以被垃圾收集

最後,垃圾收集可能也需要一些時間。
爲什麼要等我們不需要使用該對象?

+0

感謝您的解釋!但我仍然不完全明白關閉和定稿之間的區別。那麼清潔對象的方法到底是什麼?我知道finalize是清理對象的垃圾回收方法。但是最終確定的方法究竟做了什麼或者不做什麼? – titorat

+0

歡迎您.'close()'和終結器具有相同的意圖並執行相同的操作:清理並釋放對象不再需要的資源。 「我知道finalize是清理對象的垃圾回收方法」是的,但是要清理對象,你必須重寫類中的'finalize()'方法。如果您不覆蓋它,該方法什麼也不做。閱讀與以下相關的javadoc:**類Object的finalize方法不執行特殊操作;它只是通常返回**。 – davidxxx

+0

這兩種方法之間的區別是'finalize()'可能永遠不會被調用或者調用非常晚(所以一些資源可能不會在某個延遲之前被釋放),而如果客戶端代碼顯式調用'close()'方法作爲釋放與對象關聯的資源的方法),只要返回'close()'的調用,就一定要釋放資源。 – davidxxx

1

顯式終止方法和finalize()之間的主要區別在於第二個不能保證被調用。它最終在垃圾收集期間被調用,這可能是誠實永遠不會發生的。讓我們考慮以下三個類。

class Foo { 
    @Override 
    public void finalize() { 
     System.out.println("Finalize Foo"); 
    } 
} 

class Bar implements Closeable { 
    @Override 
    public void close() { 
     System.out.println("Close Bar"); 
    } 
} 

class Baz implements AutoCloseable { 
    @Override 
    public void close() { 
     System.out.println("Close Baz"); 
    } 
} 

第一個覆蓋從Object繼承了finalize()方法。 FooBar實現了由ARM(自動資源管理)處理的兩個接口。

Foo foo = new Foo(); 
new Foo(); 
try (Bar bar = new Bar(); Baz baz = new Baz()) { // this is ARM 
    System.out.println("termination example"); 
} 
Bar bar = null; 
try { 
    bar = new Bar(); 
    // ... 
} finally { 
    if (bar != null) { 
     bar.close(); 
    } 
} 

這個例子應該返回:

termination example 
Close Baz 
Close Bar 
Close Bar 

Foofinalize()方法被從來沒有所謂的,因爲Foo不是垃圾收集。 JVM具有可用資源,因此爲了優化性能,它不執行垃圾收集。此外 - 如果儘管完成應用程序的事實資源不是垃圾收集。即使是第二個創建的Foo實例也不是垃圾收集,因爲有足夠的資源讓JVM茁壯成長。

第二個與ARM是好了很多,因爲它創造了兩個資源(一個實施java.io.Closeable和一個執行java.lang.AutoCloseable,值得一提的是,Closeable延伸AutoCloseable,這就是爲什麼它是適用於ARM)。 ARM保證這些資源被關閉,當另一個拋出時關閉一個等等。第二個提供了類似於ARM的東西,但節省了大量不必要的樣板代碼。

東西讓你成爲更好的開發:

但它仍然是不完美的。程序員記住關閉對象仍然有一個負擔。 Java中沒有析構函數會迫使開發人員記住關閉資源,記得使用ARM等等。有一個很好的設計模式(由Venkat Subramaniam解釋) - Loan Pattern。貸款模式的一個簡單的例子:

class Loan { 
    private Loan() { 
    } 

    public Loan doSomething(int m) { 
     System.out.println("Did something " + m); 
     if (new Random().nextBoolean()) { 
      throw new RuntimeException("Didn't see that commming"); 
     } 
     return this; 
    } 

    public Loan doOtherThing(int n) { 
     System.out.println("Did other thing " + n); 
     return this; 
    } 

    private void close() { 
     System.out.println("Closed"); 
    } 

    public static void loan(Consumer<Loan> toPerform) { 
     Loan loan = new Loan(); 
     try { 
      toPerform.accept(loan); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      loan.close(); 
     } 
    } 
} 

您可以使用它像:

class Main { 
    public static void main(String[] args) { 
     Loan.loan(loan -> loan.doOtherThing(2) 
       .doSomething(3) 
       .doOtherThing(3)); 
    } 
} 

它減輕了關閉資源的負擔開發商,因爲它已經爲他處理。如果其中一種方法拋出,則處理它,開發人員不必費心。 close方法和構造函數是私有的,不會誘使開發人員使用它們。

相關問題