31
2015/03/10 讀書會分享 Effective Java 摘選條目分享 1 - 物件、複合、可變性、Leak Kane

Effective java 摘選條目分享 1 - 物件、複合、可變性、leak

Embed Size (px)

Citation preview

Page 1: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

2015/03/10 讀書會分享

Effective Java摘選條目分享 1

- 物件、複合、可變性、Leak

Kane

Page 2: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

關於 Effective Java 一書

Joshua Bloch - Google的首席Java架構師

學習語言:語法、詞彙、用法

進階讀物

條列式

Page 3: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

報告大綱

物件 - 創建及銷毀 (ch.2)

複合 - 是否真的需要繼承? (p.34 & no.16)

可變性 (no.15)

Member Class 注意事項 (no.22)

Page 4: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

You should already know ...

class

instance

reference

gc

Page 5: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

You should already know ...

class

instance

reference

gc

藍圖

蓋出來的房子

門牌號碼、地址

拆房子、垃圾回收

Page 6: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

創建及銷毀 instance1. Static Factory

2. Builder

3. Singleton

4. 不必要的創建

5. 過期的引用

Page 7: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

Static Factory

1. 名稱例:Bitmap.createBitmap(...), Toast.makeText(...)

2. 管理例:Flyweight pattern (不用每次都創新的 instance)

3. 彈性可以返回 sub-class instance

Page 8: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

Builder

管理建構參數

new AlertDialog.Builder(context) .setTitle("Exit") .setMessage("Are you sure?") .setPositiveButton("Yes", onUserExitListener) .setNegativeButton("No", null) .show();

Page 9: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

Singleton

三種方法:

1. Field - public static final

2. Static Factory - getInstance()

3. Enum ← 推薦

Page 10: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

不必要的創建 1/2class Person { Date birthDate; boolean isBabyBoomer() { 創建 Calendar instance 設定為 1946/1/1,再取得 Date instance 設定為 1965/1/1,再取得 Date instance 比較 birthDate 是否落於上面兩者之間

}} 1. 每次被調用時,都要重複做,而且一模一樣

2. 創建 Calendar instance 的代價

Page 11: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

不必要的創建 2/2Long sum = 0L;for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i;} 1. autoboxing:創建 2^31個 Long instance!

2. 基本類型優先於裝箱基本類型

Page 12: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

Where’s leak?class Stack { Object[] elements; int size = 0; .... push(Object e) { ensureCapacity(); elements[size++] = e; } pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; }}

Page 13: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

過期的引用

class Stack { Object[] elements; int size = 0; .... push(Object e) { ensureCapacity(); elements[size++] = e; } pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; }}

reference 仍然指著 instance,

gc 時不會被清除,

但意義上,pop 後應該脫離 stack

Page 14: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

無意識的對象保持

1. 自己管理的物件

結束使用時、考慮被別人取用的情況

2. 別人管理的物件

該 instance 的生命週期之決定權?

3. Callback 物件

非同步調用

Page 15: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

Android開發中常見

● Static field

● Activity(Context)

● Handler

● Callback

● 生命週期概念混淆 (onCreate/onDestroy vs new/gc)

Page 16: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

複合優先於繼承

用 has-A 取代 is-A

更彈性、減少束縛

Page 17: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak
Page 18: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

考慮以下需求

想要監控物件放入 set 的次數,怎麼做?

Page 19: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

繼承 set,監控所有 addclass InstrumentedHashSet<E> extends HashSet<E> {

add(E e) { } addAll(Collection<? extends E> c) { }}

Page 20: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

繼承 set,監控所有 addclass InstrumentedHashSet<E> extends HashSet<E> { addCount = 0; // 計算 add 的次數

add(E e) { addCount++; } addAll(Collection<? extends E> c) { addCount += c.size(); }}

Page 21: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

繼承 set,監控所有 addclass InstrumentedHashSet<E> extends HashSet<E> { addCount = 0; // 計算 add 的次數

add(E e) { addCount++; return super.add(e); } addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); }}

Page 22: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

實際跑看看

class InstrumentedHashSet<E> extends HashSet<E> { addCount = 0; // 計算 add 的次數 add(E e) { addCount++; return super.add(e); } addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); }}

Set<String> set = new InstrumentedHashSet<String>();

List<String> list = Arrays.asList(“a”, “b”, “c”);

set.addAll(list);

int count = ((InstrumentedHashSet) list).getAddCount();

Page 23: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

出乎預料

執行結果為 6 !

Page 24: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

繼承一個類別,便會產生依賴

父類別有可能改版,子類別變得不穩定!

計數功能:本質上只是一個實現細節,不是HashSet的一部分

真的需要繼承嗎?

HashSet addAll() 呼叫了自己的 add()

Page 25: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

以複合(has-a)取代繼承(is-a)class ForwardingSet<E> { addCount = 0; // 計算 add 的次數

Set<E> set; // 實際存放的容器

add(E e) { addCount++; return set.add(e); } addAll(Collection<? extends E> c) { addCount += c.size(); return set.addAll(c); }}

不論 set 裡面怎麼實作,

都不影響 addCount

Page 26: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

可變性最小化 1/2不可變 immutable

例子:String, BigInteger等

優點:自由共享、不易誤用(繼承、thread-safe等)

缺點:不同的值(狀態)就需要不同的instance

配套類(companing class):例 StringBuilder, BitSet 等

Page 27: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

可變性最小化 2/2作法:

1. 不提供 mutator2. final class3. final field4. private field5. 確保可變組件無法被使用(access)

a. 必要時須用 defensive copy

Page 28: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

兩種 Member class

A a = new A();B b = a.new B(); // 需要 a

C c = new C();

A 是 enclosing classclass A { class B { ... } static class C { ... } ...}

b 需要 a 的狀態

c 不需要 a 的狀態

Page 29: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

隱含的 referenceclass A { class B { ... }}

class Client { void main() { A a = new A(); B b = a.new B(); a = null; ... System.gc(); ... }}

原本 a 指向的 instance 不會被回收!

B 為 nonstatic,b 隱含 a 的 reference。

Page 30: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

優先考慮 Static Member Class

除非需要 enclosing class 的 instance 的狀態

Page 31: Effective java   摘選條目分享 1 - 物件、複合、可變性、leak

Q & A