代碼首先是給人看的诡延,所以寫(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ì)象
第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ù)其中baseUrl
和cacheDir
是必傳參數(shù)晦闰。
如果直接用構(gòu)造器傳遞參數(shù)的方式來(lái)創(chuàng)建實(shí)例弊端是:
- 構(gòu)造器參數(shù)冗長(zhǎng)而且不直觀必須參照著源碼或者文檔來(lái)填寫(xiě)參數(shù)放祟,而且容易出錯(cuò),假如參數(shù)之間
String
類型較多容易填錯(cuò) 鹅髓。 - 在眾多參數(shù)中舞竿,必傳參數(shù)不明顯。
建造者模式很容易的解決了這兩個(gè)弊端:
- 參數(shù)通過(guò)單獨(dú)的方法進(jìn)行設(shè)置窿冯,方法的名字描述了該參數(shù)的意思非常直觀例如
setOkhttpConfig
設(shè)置Okhttp
配置骗奖。不需要的參數(shù)不調(diào)用setXXX
方法保證了代碼的整潔。由于每個(gè)參數(shù)都是一個(gè)方法來(lái)配置醒串,也不容易出錯(cuò)执桌。 - 必傳參數(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.Arrays
、java.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)的例子:
- 創(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ì)被重用毁涉。
- 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;
}
}
- 自動(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)用終止方法.
例如:InputStream
的close
方法势木。
缺點(diǎn):
- 終結(jié)方法不能保證及時(shí)執(zhí)行蛛倦。
- 可移植性問(wèn)題。由于終結(jié)方法的調(diào)用以來(lái)jvm垃圾回收算法跟压,所以不同的jvm很可能會(huì)有不同的結(jié)果胰蝠。
- 終結(jié)方法執(zhí)行的線程(也就是GC的線程)有可能比你應(yīng)用程序的任何線程優(yōu)先級(jí)都低。假如利用終結(jié)方法來(lái)釋放內(nèi)存震蒋,程序都已經(jīng)
OutOfMemoryError
死掉了茸塞,終結(jié)方法還沒(méi)有調(diào)用。 - 終結(jié)方法不會(huì)拋出異常查剖。終結(jié)者方法中如果有異常則不會(huì)打印出任何信息钾虐,且終結(jié)方法會(huì)停止,這樣對(duì)找bug來(lái)說(shuō)真是難上加難笋庄。
- 使用終結(jié)方法有非常嚴(yán)重的性能損失效扫。書(shū)上舉例說(shuō):正常創(chuàng)建和銷毀一個(gè)簡(jiǎn)單對(duì)象時(shí)間大約為5.6ns。增加一個(gè)終結(jié)方法使時(shí)間增加到2400ns直砂。慢了大約430倍菌仁。
既然java提供了終結(jié)方法那么它肯定是有用途的。
用途:
- 安全網(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ò)鲫寄,是否值得這么做。 - 本地對(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é)方法:
- 終結(jié)方法必須調(diào)用父類的終結(jié)方法荠列,否則當(dāng)類繼承的情況下父類就永遠(yuǎn)不可能調(diào)用終結(jié)方法了。這個(gè)代碼使用
try{}finally{}
代碼塊在finally{}
中調(diào)用super.finalize();
保證就算發(fā)生異常也一定會(huì)執(zhí)行父類的終結(jié)方法载城。 - 為了防止粗心大意忘記調(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
}
};
......
}