建立和銷毀對象
1. 考慮用靜态方法代替構造器
例如
public static Boolean valueOf(boolean b){
return b > Boolean.TRUE : Boolean.FALSE
}
優勢
- 有名稱
- 不必每次調用他們的的時候都建立一個新對象
- 可以傳回員傳回類型的任何子類型的對象
缺點
- 類如果不含共有的或者搜保護的構造器沒,就不能被子類化
- 他們于其他的靜态方法實際上沒有任何差別
2.遇到多個構造器參數時要考慮用建構器
JavaBeans
調用一個無參構造器來建立對象,然後調用 setter方法來設定每個必要的參數以及各每個相關的可選參數
缺點:
- 因為被分到幾個調用中,在建構過程中可能處于不一緻的狀态。
- 阻止了把類做成不可變的可能,需求程式員付出額外的努力來確定它的線程安全
Builder模式(建造者模式)
如果類的構造器或者靜态工廠中具有多個參數,設計這種類時,Builder模式是不錯的選擇。
// 例如
public class Course {
private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
/**
* question & answer
*/
private String courseQA;
public Course(CourseBuilder courseBuilder) {
this.courseName = courseBuilder.courseName;
this.coursePPT = courseBuilder.coursePPT;
this.courseVideo = courseBuilder.courseVideo;
this.courseArticle = courseBuilder.courseArticle;
this.courseQA = courseBuilder.courseQA;
}
@Override
public String toString() {
return "Course{" +
"courseName='" + courseName + '\'' +
", coursePPT='" + coursePPT + '\'' +
", courseVideo='" + courseVideo + '\'' +
", courseArticle='" + courseArticle + '\'' +
", courseQA='" + courseQA + '\'' +
'}';
}
public static class CourseBuilder {
private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
/**
* question & answer
*/
private String courseQA;
public CourseBuilder buildCoureseName(String courseName) {
this.courseName = courseName;
return this;
}
public CourseBuilder buildCoursePPT(String coursePPT) {
this.coursePPT = coursePPT;
return this;
}
public CourseBuilder buildCourseVideo(String courseVideo) {
this.courseVideo = courseVideo;
return this;
}
public CourseBuilder buildCourseArticle(String courseArticle) {
this.courseArticle = courseArticle;
return this;
}
public CourseBuilder buildCourseQA(String courseQA) {
this.courseQA = courseQA;
return this;
}
public Course build() {
return new Course(this);
}
}
}
// 測試
Course course = new Course.CourseBuilder()
.buildCoureseName("Java設計模式精講")
.buildCoursePPT("Java設計模式PPT")
.buildCourseVideo("Java設計模式視訊")
.build();
System.out.println(course);
3.用私有構造器或者枚舉類型強化Singleton屬性
Singleton是指僅僅被執行個體化一次的類。
注意:享有特權的用戶端可以借助 AccessibleObject.setAccessible方法,通過反射機制調用私有構造器
4.通過私有構造器強化不可執行個體化的能力
企圖通過将類做成抽象類來強制該類不可被執行個體化,是行不通的
5.避免建立不必要的對象
要優先使用基本類型而不是裝箱基本類型,要當心無意思的自動裝箱
6.消除過期的對象引用
/**
* @author stone
* @des 記憶體洩露示例
* @date 2018/12/5/005 8:40
**/
public class Stack {
private Object[] element;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
}
public void push(Object e) {
ensureCapacity();
element[size++] = e;
}
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
// 注意下面這行代碼會引起記憶體洩露
// 如果一個棧是先增長,然後再收縮,那麼,從棧中彈出來的對象将不會被當做垃圾回收,即使使用棧的程式不再引用這些對象,他們也不會被回收
// 棧内部維護着這些對象的過期引用。過期引用:永遠也不會再被解除的引用。
// 本例中 凡是element數組中的活動部分之外的任何引用都是過期的。活動部分:element中下标小于size的那些元素
// return element[--size];
Object result = element[--size];
// 解決方法如下 消除過期引用
// Eliminate obsolete reference
element[size] = null;
return result;
}
/**
* ensure space for at least one more element,roughly
* doubling the capacity each time the array needs to grow
*/
private void ensureCapacity() {
if (element.length == size) {
element = Arrays.copyOf(element, 2 * size + 1);
}
}
}
總結 : 過期的對象引用 可能會引起記憶體洩露
隻要類是自己管理記憶體,程式員就應該警惕記憶體洩露的問題。
記憶體洩露常見來源
- 隻要類是自己管理記憶體,程式員就應該警惕記憶體洩露的問題。
- 緩存
- 監聽器和其他回調
7.避免使用終結方法
終結方法(finalizer)通常是不可預測的,很危險的,也一般是不必要的。
Java語言規範不僅不保證終結方法會被及時地執行,而且根本就不保證它們會被執行。
不應該依賴終結方法來更新重要的持久狀态。
System.gc System.runFinalization這兩個方法确實增加了終結方法被執行的機會,但它們并不保證終結方法一定會被執行。
終結方法有一個非常嚴重的(Severe)性能損失。
用終結方法建立和銷毀對象比正常要慢上百倍。