Effective Java——?jiǎng)?chuàng)建和銷毀對(duì)象

Android.jpg

代碼首先是給人看的诡延,所以寫(xiě)代碼要有寫(xiě)詩(shī)一樣的感覺(jué)(哈哈雷軍說(shuō)的)鸦概,無(wú)論是寫(xiě)邏輯奸忽、中間件或是寫(xiě)框架都是如此。
想要寫(xiě)好代碼首先基礎(chǔ)一定要好改鲫,所以我最近重新看了Effective Java诈皿,雖然這已經(jīng)不是第一次看了但是還是有很多可以學(xué)習(xí)的地方林束。
本系列文章是總結(jié)Effective Java文章中我認(rèn)為最重點(diǎn)的內(nèi)容,給很多沒(méi)時(shí)間看書(shū)的朋友以最短的時(shí)間看到這本書(shū)的精華稽亏。

第二章創(chuàng)建和銷毀對(duì)象

目錄.png

第1條:考慮用靜態(tài)方法代替構(gòu)造器

優(yōu)勢(shì)

第一大優(yōu)勢(shì)在于壶冒,他們有名稱。

這個(gè)很好理解截歉,他主要解決的是構(gòu)造方法的重載問(wèn)題胖腾,如下代碼:

public class CustomDialog {
    //構(gòu)造一個(gè)有標(biāo)題,有內(nèi)容怎披,有兩個(gè)按鈕的Dialog
    public CustomDialog(String title,
                        String msg,
                        String leftButton,
                        String rightButton,
                        Object leftOnClickListener,
                        Object rightOnClickListener) {
    }
    //構(gòu)造一個(gè)無(wú)標(biāo)題胸嘁,有內(nèi)容,有兩個(gè)按鈕的Dialog
    public CustomDialog(
            String msg,
            String leftButton,
            String rightButton,
            Object leftOnClickListener,
            Object rightOnClickListener) {
        this(null, msg, leftButton, rightButton, leftOnClickListener, rightOnClickListener);
    }
    //構(gòu)造一個(gè)有標(biāo)題凉逛,有內(nèi)容帝璧,有一個(gè)按鈕的Dialog
    public CustomDialog(String title,
                        String msg,
                        String leftButton,
                        Object leftOnClickListener) {
        this(title, msg, leftButton, null, leftOnClickListener, null);
    }
}

如果程序中的公共組件這么寫(xiě)褥琐,那么調(diào)用這個(gè)Dialog組件將是非常麻煩的一件事,每次創(chuàng)建的時(shí)候都要看文檔狂打,或者點(diǎn)進(jìn)去看源碼非常不直觀书斜,如果將代碼修改成如下方式:

public class CustomDialog {
    //構(gòu)造一個(gè)有標(biāo)題诬辈,有內(nèi)容,有兩個(gè)按鈕的Dialog
    public static CustomDialog createCustomDialog(){
        return null;
    }
    //構(gòu)造一個(gè)無(wú)標(biāo)題荐吉,有內(nèi)容焙糟,有兩個(gè)按鈕的Dialog
    public static CustomDialog createNoTitleCustomDialog(){
        return null;
    }
    //構(gòu)造一個(gè)有標(biāo)題,有內(nèi)容样屠,有一個(gè)按鈕的Dialog
    public static CustomDialog createSingleButtonCustomDialog(){
        return null;
    }
}
//使用測(cè)試代碼
public class MainActivity extends Activity {
    private CustomDialog customDialog;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //很直觀的展示了你創(chuàng)建的Dialog的形式
        customDialog = CustomDialog.createCustomDialog();
        customDialog = CustomDialog.createNoTitleCustomDialog();
        customDialog = CustomDialog.createSingleButtonCustomDialog();
    }

這種靜態(tài)方法因?yàn)樗忻执┐椋詣?chuàng)建對(duì)象實(shí)例的時(shí)候非常直觀。查看代碼的人也很清楚就可以看到你創(chuàng)建的Dialog是什么形式的痪欲,是否有標(biāo)題悦穿,是否是單個(gè)Button,不用查看文檔或者進(jìn)入源碼進(jìn)行查看业踢。

第二大優(yōu)勢(shì)在于栗柒,不必在每次調(diào)用他們的時(shí)候創(chuàng)建一個(gè)新的對(duì)象。

主要應(yīng)用于單例模式知举,如下代碼:

public class SingletonClass {
        private static volatile SingletonClass instance = null;
        public static SingletonClass getInstance() {
            if (null == instance)
                synchronized (SingletonClass.class) {
                    if (null == instance) {
                        instance = new SingletonClass();
                    }
                }
            return instance;
        }
        private SingletonClass() {}
    }
第三大優(yōu)勢(shì)在于瞬沦,它們可以返回原返回類型的任何子類型的對(duì)象。

面向接口編程雇锡,創(chuàng)建對(duì)象的方法返回接口逛钻,如下代碼:

//Mock本地測(cè)試數(shù)據(jù)的類
public class MockDataRespsitoryManager implements IDataRepositoryManager {
    ......
}
//訪問(wèn)網(wǎng)絡(luò)的管理類
public class DataRepositoryManager implements IDataRepositoryManager {
    ......
}
@Singleton
@Module
public class DataRepositoryModule {
     ......
    @Singleton
    @Provides
    public IDataRepositoryManager providerRepositoryManager(Retrofit retrofit, RxCache rxCache) {
        return new DataRepositoryManager(retrofit, rxCache);
    }
    @Singleton
    @Provides
    @MockData
    public IDataRepositoryManager providerMockRepositoryManager(Application application, @Nullable DataRepositoryModule.MockDataConfig mockDataConfig) {
        return new MockDataRespsitoryManager(application,mockDataConfig);
    }
    ......
}
//構(gòu)造方法傳入的是上兩個(gè)方法返回的對(duì)象
public class BaseModel {
    protected IDataRepositoryManager repositoryManager;
    public BaseModel(IDataRepositoryManager repositoryManager){
        this.repositoryManager = repositoryManager;
    }
    public void onDestory(){
        this.repositoryManager = null;
    }
}

如上代碼片段BaseModel類的構(gòu)造方法在正常情況下接收providerRepositoryManager返回的對(duì)象鏈接網(wǎng)絡(luò)獲取數(shù)據(jù),開(kāi)發(fā)前期接收providerMockRepositoryManager返回的對(duì)象從本地讀取Mock數(shù)據(jù)進(jìn)行調(diào)試遮糖。

第四大優(yōu)勢(shì)在于绣的,在創(chuàng)建參數(shù)化實(shí)例的時(shí)候,他們使代碼變得更加簡(jiǎn)潔。

主要用在創(chuàng)建泛型對(duì)象屡江,如下代碼:

public class AClass{
        public static class BClass{
            public static class CClass{
                public static class DClass{}
            }
        }
    }
//普通創(chuàng)建Map集合實(shí)例芭概,非常冗長(zhǎng)。
Map<AClass.BClass.CClass.DClass,AClass.BClass.CClass.DClass> map = new HashMap<AClass.BClass.CClass.DClass, AClass.BClass.CClass.DClass>();

//應(yīng)用靜態(tài)工廠方法
public static <K,V> HashMap<K,V> newInstance(){
        return new HashMap<K,V>();
}
//應(yīng)用靜態(tài)工廠方法創(chuàng)建泛型對(duì)象代碼簡(jiǎn)潔了很多惩嘉。
Map<AClass.BClass.CClass.DClass,AClass.BClass.CClass.DClass> map = newInstance();

缺點(diǎn)

主要缺點(diǎn)在于罢洲,類如果不含公有的或者受保護(hù)的構(gòu)造器,就不能被子類化文黎。

還是拿單例模式來(lái)舉例子:

public class SingletonClass {
        private static volatile SingletonClass instance = null;
        public static SingletonClass getInstance() {
            if (null == instance)
                synchronized (SingletonClass.class) {
                    if (null == instance) {
                        instance = new SingletonClass();
                    }
                }
            return instance;
        }
        //構(gòu)造方法是private不是public也不是protected,所以單例不能實(shí)現(xiàn)繼承
        private SingletonClass() {}
    }
第二個(gè)缺點(diǎn)在于惹苗,它們與其他的靜態(tài)方法實(shí)際上沒(méi)有任何區(qū)別。

創(chuàng)建對(duì)象靜態(tài)方法和其他的靜態(tài)方法沒(méi)有任何區(qū)別耸峭,所以如果命名不規(guī)范桩蓉,使用者很難找到創(chuàng)建對(duì)象的靜態(tài)方法。
命名規(guī)則例如:

public static Object createXXXX(){
        return null;
}
public static Object factoryXXXX(){
        return null;
}
public static Object newInstance(){
        return null;
}

上面代碼片段只是一種假設(shè)劳闹,每個(gè)項(xiàng)目的命名規(guī)范不一樣院究。只要遵循同一套規(guī)范就會(huì)使代碼清晰可讀。

第2條:遇到多個(gè)構(gòu)造參數(shù)時(shí)要考慮用建造器

建造者模式:是將一個(gè)復(fù)雜的對(duì)象的構(gòu)建與它的表示分離本涕,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示业汰。
概念性的東西真是不好理解,簡(jiǎn)單解釋為什么要用建造者模式菩颖,如果創(chuàng)建一個(gè)對(duì)象需要很多參數(shù)样漆,有必傳參數(shù)有非必傳參數(shù)最好用建造者模式。
如下代碼片段:
代碼源碼點(diǎn)擊這里
代碼涉及到dagger2知識(shí)點(diǎn)擊這里查看簡(jiǎn)介

@Singleton
@Module
public class AppDelegateConfig {

    private final String baseUrl;
    private final File cacheDir;
    private final RetrofitConfig retrofitConfig;
    private final DataRepositoryModule.OkhttpConfig okhttpConfig;
    private final DataRepositoryModule.RxCacheConfig rxCacheConfig;
    private final DataRepositoryModule.MockDataConfig mockDataConfig;
    private final IHttpErrorHandler iHttpErrorHandler;
    private final IHttpResponseHandler iHttpResponseHandler;

    private AppDelegateConfig(Builder builder){
        baseUrl = builder.baseUrl;
        cacheDir = builder.cacheDir;
        retrofitConfig = builder.retrofitConfig;
        okhttpConfig = builder.okhttpConfig;
        rxCacheConfig = builder.rxCacheConfig;
        mockDataConfig = builder.mockDataConfig;
        iHttpErrorHandler = builder.iHttpErrorHandler;
        iHttpResponseHandler = builder.iHttpResponseHandler;
    }
    @Singleton
    @Provides
    public String providerBaseUrl() {
        return baseUrl;
    }
    @Singleton
    @Provides
    public File providerCacheDir() {
        return cacheDir;
    }
    @Singleton
    @Provides
    @Nullable
    public RetrofitConfig providerRetrofitConfig() {
        return retrofitConfig;
    }
    @Singleton
    @Provides
    @Nullable
    public DataRepositoryModule.OkhttpConfig providerOkhttpConfig() {
        return okhttpConfig;
    }
    @Singleton
    @Provides
    @Nullable
    public DataRepositoryModule.RxCacheConfig providerRxCacheConfig() {
        return rxCacheConfig;
    }
    @Singleton
    @Provides
    @Nullable
    public DataRepositoryModule.MockDataConfig providerMockDataConfig(){
        if(null == mockDataConfig){
             return new DefaultMockDataConfig();
        }
        return mockDataConfig;
    }
    @Singleton
    @Provides
    public IHttpErrorHandler providerIHttpErrorHandler(Application application) {
        if(null == iHttpErrorHandler){
            return new DefaultHttpErrorHandler(application);
        }
        return iHttpErrorHandler;
    }
    @Singleton
    @Provides
    public IHttpResponseHandler providerIHttpResponseHandler() {
        if(null == iHttpResponseHandler){
            return new DefaultHttpResponseHandler();
        }
        return iHttpResponseHandler;
    }

    public static class Builder{

        private String baseUrl;
        private File cacheDir;
        private RetrofitConfig retrofitConfig;
        private DataRepositoryModule.OkhttpConfig okhttpConfig;
        private DataRepositoryModule.RxCacheConfig rxCacheConfig;
        private DataRepositoryModule.MockDataConfig mockDataConfig;
        private IHttpErrorHandler iHttpErrorHandler;
        private IHttpResponseHandler iHttpResponseHandler;

        public Builder(String baseUrl, File cacheDir){
            this.baseUrl = baseUrl;
            this.cacheDir = cacheDir;
        }
        public Builder setRetrofitConfig(RetrofitConfig retrofitConfig) {
            this.retrofitConfig = retrofitConfig;
            return this;
        }
        public Builder setOkhttpConfig(DataRepositoryModule.OkhttpConfig okhttpConfig) {
            this.okhttpConfig = okhttpConfig;
            return this;
        }
        public Builder setRxCacheConfig(DataRepositoryModule.RxCacheConfig rxCacheConfig) {
            this.rxCacheConfig = rxCacheConfig;
            return this;
        }
        public Builder setIHttpErrorHandler(IHttpErrorHandler iHttpErrorHandler){
            this.iHttpErrorHandler = iHttpErrorHandler;
            return this;
        }

        public Builder setiHttpResponseHandler(IHttpResponseHandler iHttpResponseHandler) {
            this.iHttpResponseHandler = iHttpResponseHandler;
            return this;
        }
        public Builder setMockDataConfig(DataRepositoryModule.MockDataConfig mockDataConfig) {
            this.mockDataConfig = mockDataConfig;
            return this;
        }
        public AppDelegateConfig builder(){
            return new AppDelegateConfig(this);
        }
    }
}

AppDelegateConfig appDelegateConfig = new AppDelegateConfig
                .Builder("baseUrl", new File("cacheDir"))
                .setOkhttpConfig(...)
                .setMockDataConfig(...)
                .setIHttpErrorHandler(...)
                .setiHttpResponseHandler(...)
                .setRetrofitConfig(...)
                .setRxCacheConfig(...)
                .builder();

如上代碼片段構(gòu)建AppDelegateConfig類實(shí)例需要8個(gè)參數(shù)其中baseUrlcacheDir是必傳參數(shù)晦闰。
如果直接用構(gòu)造器傳遞參數(shù)的方式來(lái)創(chuàng)建實(shí)例弊端是:

  1. 構(gòu)造器參數(shù)冗長(zhǎng)而且不直觀必須參照著源碼或者文檔來(lái)填寫(xiě)參數(shù)放祟,而且容易出錯(cuò),假如參數(shù)之間String類型較多容易填錯(cuò) 鹅髓。
  2. 在眾多參數(shù)中舞竿,必傳參數(shù)不明顯。

建造者模式很容易的解決了這兩個(gè)弊端:

  1. 參數(shù)通過(guò)單獨(dú)的方法進(jìn)行設(shè)置窿冯,方法的名字描述了該參數(shù)的意思非常直觀例如setOkhttpConfig設(shè)置Okhttp配置骗奖。不需要的參數(shù)不調(diào)用setXXX方法保證了代碼的整潔。由于每個(gè)參數(shù)都是一個(gè)方法來(lái)配置醒串,也不容易出錯(cuò)执桌。
  2. 必傳參數(shù)通過(guò)Builder建造者的構(gòu)造方法傳入,保證必須設(shè)置芜赌。

第3條:用私有構(gòu)造器或者枚舉類型強(qiáng)化Singleton屬性

1.單例模式要將構(gòu)造方法設(shè)置成私有的private仰挣,代碼在上文中已經(jīng)多次提到這里就不再贅述了。
2.通過(guò)枚舉來(lái)實(shí)現(xiàn)單例模式缠沈,如下代碼:

public enum Singleton {
      //定義一個(gè)枚舉的元素膘壶,它就是 Singleton 的一個(gè)實(shí)例
     INSTANCE;  
     public void doSomeThing() {  
         // do something...
     }  
 }

1)線程安全
2)防止序列化
3)防止反射攻擊
這篇文章分析的很透徹:請(qǐng)點(diǎn)擊

第4條:通過(guò)私有構(gòu)造器強(qiáng)化不可實(shí)例的能力

主要說(shuō)的就是工具類(utility class)错蝴,例如jdk自帶的java.util.Arraysjava.util.Collections等他們類中全都是靜態(tài)方法和靜態(tài)常量颓芭,實(shí)例化和子類化對(duì)他們一點(diǎn)意義都沒(méi)有顷锰,所以通過(guò)私有化構(gòu)造方法來(lái)控制他們不能被實(shí)例化或子類化。

public class Arrays {
    // Suppresses default constructor, ensuring non-instantiability.
    private Arrays() {}
    ......
}

public class Collections {
    // Suppresses default constructor, ensuring non-instantiability.
    private Collections() {
    }
    ......
}

第5條:避免創(chuàng)建不必要的對(duì)象

防止創(chuàng)建不必要的對(duì)象亡问,浪費(fèi)內(nèi)存也減慢了程序的執(zhí)行速度官紫。
介紹了幾個(gè)常見(jiàn)的例子:

  1. 創(chuàng)建字符串
String s = new String("stringette");
//應(yīng)該優(yōu)化成
String s = "stringette";

第一行代碼每次執(zhí)行的時(shí)候都創(chuàng)建一個(gè)新的String實(shí)例,非常沒(méi)有必要州藕。
第二行代碼通過(guò)虛擬機(jī)進(jìn)行優(yōu)化束世,在同一臺(tái)虛擬機(jī)中運(yùn)行代碼,只要他們包含相同的字符串字面常量床玻,該對(duì)象實(shí)例就不會(huì)重新創(chuàng)建會(huì)被重用毁涉。

  1. DateUtils 工具類
public class DateUtils {
    private DateUtils(){}
    //根據(jù)pattern來(lái)格式化輸入的millis
    public static String dateFormat(long millis, String pattern) {
        //假如這個(gè)工具類用來(lái)列表中,這個(gè)對(duì)象會(huì)非常頻繁的創(chuàng)建笨枯,造內(nèi)存泄漏薪丁,程序運(yùn)行減慢
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        Date date = new Date(millis);
        String dateString = simpleDateFormat.format(date);
        return dateString;
    }
}
//改進(jìn)版的時(shí)間工具類
public class DateUtils {
    //靜態(tài)對(duì)象只在類加載的時(shí)候創(chuàng)建一次,有效的解決了上面頻繁創(chuàng)建對(duì)象造成的內(nèi)存泄漏問(wèn)題
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
    private DateUtils(){}
    //根據(jù)pattern來(lái)格式化輸入的millis
    public static String dateFormat(long millis, String pattern) {
        simpleDateFormat.applyPattern(pattern);
        Date date = new Date(millis);
        String dateString = simpleDateFormat.format(date);
        return dateString;
    }
}
  1. 自動(dòng)裝箱
public class TestClass {
        public static void main(String[] args) {
            Long sum = 0L;
            for (long i = 0; i < Integer.MAX_VALUE; i++) {
                sum += i;
            }
            System.out.println(sum);
        }
    }

這段代碼的結(jié)果是沒(méi)有問(wèn)題的馅精,但是由于Java的自動(dòng)裝箱機(jī)制,創(chuàng)造出了大約Integer.MAX_VALUE個(gè)多余的Long實(shí)例粱檀,造成內(nèi)存泄漏洲敢,程序運(yùn)行減慢。
所以要優(yōu)先使用基本類型進(jìn)行計(jì)算茄蚯,要當(dāng)心無(wú)意識(shí)的自動(dòng)裝箱压彭。

第6條:消除過(guò)期的對(duì)象引用

只要類是自己管理內(nèi)存,程序員就應(yīng)該警惕內(nèi)存泄漏問(wèn)題渗常。
Java 內(nèi)存回收就不再這篇文章進(jìn)行討論壮不,簡(jiǎn)單的理解是一個(gè)對(duì)象沒(méi)有任何的強(qiáng)引用這個(gè)對(duì)象就會(huì)在內(nèi)存回收的時(shí)刻被回收掉
如下代碼例子:

public static class Stack {
        private Object[] elements;
        private int size = 0;
        private static final int DEFAULT_INITIAL_CAPACITY = 16;
        public Stack() {
            elements = new Object[DEFAULT_INITIAL_CAPACITY];
        }
        public void push(Object obj) {
            ensureCapacity();
            elements[size++] = obj;
        }
        //彈出元素會(huì)造成內(nèi)存泄漏皱碘,由于棧中的每個(gè)對(duì)象都是強(qiáng)引用的询一,
        //雖然在這個(gè)地方將元素取出size也進(jìn)行了收縮,但是彈出對(duì)象的強(qiáng)引用還是一直由elements數(shù)組進(jìn)行持有癌椿,
        //在垃圾回收的時(shí)候取法將彈出的對(duì)象進(jìn)行銷毀造成了內(nèi)存泄漏
        public Object pop() {
            if (0 == size) {
                throw new EmptyStackException();
            }
            return elements[--size];
        }
        private void ensureCapacity() {
            if (elements.length == size) {
                elements = Arrays.copyOf(elements, 2 * size + 1);
            }
        }
    }
//改進(jìn)版的void pop(); 方法
//在彈出元素的同時(shí)健蕊,收縮列表,將列表中對(duì)這個(gè)元素的強(qiáng)引用設(shè)置成null踢俄,
//這樣這個(gè)彈出的對(duì)象在列表中就沒(méi)有強(qiáng)引用了缩功,他的聲明周期完全取決于外部如何用它,
public Object pop() {
            if (0 == size) {
                throw new EmptyStackException();
            }
            Object obj = elements[--size];
            elements[size] = null;
            return obj;
}

第7條:避免使用終結(jié)方法

終結(jié)方法(finalizer)通常是不可預(yù)測(cè)的都办,也是很危險(xiǎn)的嫡锌,一般情況下是不必須要的虑稼。根據(jù)經(jīng)驗(yàn):應(yīng)該避免使用。

建議:所有需要銷毀的對(duì)象都必須顯示的調(diào)用終止方法.
例如:InputStreamclose方法势木。

缺點(diǎn):

  1. 終結(jié)方法不能保證及時(shí)執(zhí)行蛛倦。
  2. 可移植性問(wèn)題。由于終結(jié)方法的調(diào)用以來(lái)jvm垃圾回收算法跟压,所以不同的jvm很可能會(huì)有不同的結(jié)果胰蝠。
  3. 終結(jié)方法執(zhí)行的線程(也就是GC的線程)有可能比你應(yīng)用程序的任何線程優(yōu)先級(jí)都低。假如利用終結(jié)方法來(lái)釋放內(nèi)存震蒋,程序都已經(jīng)OutOfMemoryError死掉了茸塞,終結(jié)方法還沒(méi)有調(diào)用。
  4. 終結(jié)方法不會(huì)拋出異常查剖。終結(jié)者方法中如果有異常則不會(huì)打印出任何信息钾虐,且終結(jié)方法會(huì)停止,這樣對(duì)找bug來(lái)說(shuō)真是難上加難笋庄。
  5. 使用終結(jié)方法有非常嚴(yán)重的性能損失效扫。書(shū)上舉例說(shuō):正常創(chuàng)建和銷毀一個(gè)簡(jiǎn)單對(duì)象時(shí)間大約為5.6ns。增加一個(gè)終結(jié)方法使時(shí)間增加到2400ns直砂。慢了大約430倍菌仁。

既然java提供了終結(jié)方法那么它肯定是有用途的。

用途:

  1. 安全網(wǎng)静暂。當(dāng)程序中有對(duì)象忘記調(diào)用顯示終結(jié)方法济丘,例如InputStream 忘記調(diào)用close方法。這個(gè)方法可以當(dāng)做安全網(wǎng)洽蛀,在這個(gè)方法中顯示調(diào)用close摹迷,雖然不能保證終結(jié)方法及時(shí)的調(diào)用,但是遲一點(diǎn)調(diào)用總比永遠(yuǎn)不釋放要好得多郊供。如果終結(jié)方法中發(fā)現(xiàn)資源還未被終止峡碉,則應(yīng)該在日志中增加一條警告。這代表程序中的bug應(yīng)該得到修復(fù)驮审。還要考慮終結(jié)方法會(huì)影響到性能上面提到過(guò)鲫寄,是否值得這么做。
  2. 本地對(duì)象头岔。在本書(shū)中作者用了本地對(duì)等體的名詞塔拳,其實(shí)就是Java編程思想中的本地對(duì)象,也就是java調(diào)用C或C++ malloc出來(lái)的內(nèi)存峡竣,這些內(nèi)存如果不顯示的調(diào)用free將無(wú)法銷毀靠抑,java的GC機(jī)制也無(wú)法銷毀這些對(duì)象,所以需要在終結(jié)方法中調(diào)用free來(lái)釋放內(nèi)存适掰。
    其實(shí)這些本地對(duì)象的銷毀一定要在程序中顯示調(diào)用釋放方法颂碧。

下面代碼是如何正確的編寫(xiě)終結(jié)方法:

  1. 終結(jié)方法必須調(diào)用父類的終結(jié)方法荠列,否則當(dāng)類繼承的情況下父類就永遠(yuǎn)不可能調(diào)用終結(jié)方法了。這個(gè)代碼使用try{}finally{}代碼塊在finally{}中調(diào)用super.finalize();保證就算發(fā)生異常也一定會(huì)執(zhí)行父類的終結(jié)方法载城。
  2. 為了防止粗心大意忘記調(diào)用父類的終結(jié)方法肌似,有了第二種寫(xiě)法,終結(jié)方法守護(hù)诉瓦。如下第二段代碼用了一個(gè)匿名Object內(nèi)部類來(lái)實(shí)現(xiàn)終結(jié)方法川队,在這個(gè)內(nèi)部類的void finalize()方法中去調(diào)用Foo類需要結(jié)束的對(duì)象,由于這個(gè)匿名Object類沒(méi)有父類所以寫(xiě)不寫(xiě)super.finalize();也無(wú)所謂睬澡。
@Override
protected void finalize() throws Throwable {
        try {
            //Finalize subclass state
        } finally {
            super.finalize();
        }
}

public class Foo{
        private final Object finalizeGuardian = new Object(){
            @Override
            protected void finalize() throws Throwable {
                //Finalize subclass state
            }
        };
        ......
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末固额,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子煞聪,更是在濱河造成了極大的恐慌斗躏,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昔脯,死亡現(xiàn)場(chǎng)離奇詭異啄糙,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)云稚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)隧饼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人静陈,你說(shuō)我怎么就攤上這事桑李。” “怎么了窿给?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)率拒。 經(jīng)常有香客問(wèn)我崩泡,道長(zhǎng),這世上最難降的妖魔是什么猬膨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任角撞,我火速辦了婚禮,結(jié)果婚禮上勃痴,老公的妹妹穿的比我還像新娘谒所。我一直安慰自己,他們只是感情好沛申,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布劣领。 她就那樣靜靜地躺著,像睡著了一般铁材。 火紅的嫁衣襯著肌膚如雪尖淘。 梳的紋絲不亂的頭發(fā)上奕锌,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音村生,去河邊找鬼惊暴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛趁桃,可吹牛的內(nèi)容都是我干的辽话。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼卫病,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼油啤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起忽肛,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤村砂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后屹逛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體础废,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年罕模,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了评腺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡淑掌,死狀恐怖蒿讥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抛腕,我是刑警寧澤芋绸,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站担敌,受9級(jí)特大地震影響摔敛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜全封,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一马昙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧刹悴,春花似錦行楞、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至恒削,卻和暖如春池颈,著一層夾襖步出監(jiān)牢的瞬間尾序,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工躯砰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留每币,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓琢歇,卻偏偏與公主長(zhǎng)得像兰怠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子李茫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容