原文地址: https://itweknow.cn/detail?id=60 俩垃,歡迎大家訪問(wèn)。
當(dāng)一個(gè)對(duì)象能夠被重用的時(shí)候但绕,就不要去創(chuàng)建新對(duì)象示绊。我們先來(lái)考慮一個(gè)比較簡(jiǎn)單的例子
String s = new String("stringette");
這個(gè)語(yǔ)句在每次被調(diào)用的時(shí)候都會(huì)創(chuàng)建一個(gè)全新的String
實(shí)例芒率,而且參數(shù)stringette
自身也是一個(gè)String實(shí)例囤耳。所以一般建議使用下面的方式來(lái)申明一個(gè)String
String s = "stringette";
下面通過(guò)幾個(gè)例子來(lái)說(shuō)明一下為啥需要避免創(chuàng)建不必要的對(duì)象。
例一
我們有一個(gè)Person
類敲董,并且類里面有一個(gè)isBabyBoomer
方法紫皇,用來(lái)校驗(yàn)這個(gè)人是否在生育高峰期出生(生育高峰期為1946年至1964年),可能我們通常的寫(xiě)法是
public class Person {
private final Date birthDate;
public Person(Date birthDate) {
this.birthDate = birthDate;
}
public boolean isBabyBoomer() {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
// 高峰期開(kāi)始時(shí)間腋寨。
calendar.set(1946, Calendar.JANUARY, 1,
0, 0, 0);
Date start = calendar.getTime();
// 高峰期結(jié)束時(shí)間。
calendar.set(1965, Calendar.JANUARY, 1,
0, 0, 0);
Date end = calendar.getTime();
// 比較化焕。
return birthDate.compareTo(start) >=0 &&
birthDate.compareTo(end) < 0;
}
}
我們來(lái)試一下調(diào)用一千萬(wàn)次這個(gè)方法所消耗的時(shí)間萄窜。
public class Test01 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
Person person = new Person(new Date());
for (int i=0; i<10000000; i++) {
person.isBabyBoomer();
}
long end = System.currentTimeMillis();
System.out.println("消耗時(shí)間:" + (end - start) + "ms");
}
}
在我的電腦上耗時(shí)在3200ms
左右,下面我們做一下修改撒桨,將生育高峰期的開(kāi)始和結(jié)束時(shí)間抽出來(lái)作為Person
類的屬性查刻,并且在靜態(tài)代碼塊中進(jìn)行賦值。
public class Person {
private final Date birthDate;
private static final Date startDate;
private static final Date endDate;
static {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
// 高峰期開(kāi)始時(shí)間凤类。
calendar.set(1946, Calendar.JANUARY, 1,
0, 0, 0);
startDate = calendar.getTime();
// 高峰期結(jié)束時(shí)間穗泵。
calendar.set(1965, Calendar.JANUARY, 1,
0, 0, 0);
endDate = calendar.getTime();
}
public Person(Date birthDate) {
this.birthDate = birthDate;
}
public boolean isBabyBoomer2() {
// 比較。
return birthDate.compareTo(startDate) >=0 &&
birthDate.compareTo(endDate) < 0;
}
}
再次測(cè)試發(fā)現(xiàn)消耗時(shí)間大概在20ms
左右谜疤,效率提高了差不多150倍佃延。
例二
我們知道在Java
中字符串如果使用+
進(jìn)行拼接的時(shí)候會(huì)創(chuàng)建新的String實(shí)例,而使用StringBuilder.append()
方法則不會(huì)創(chuàng)建新的實(shí)例夷磕。下面我們分別用兩種方式進(jìn)行十萬(wàn)次的字符串拼接履肃。
public class Test02 {
public static void main(String[] args) {
method01();
method02();
}
public static void method01() {
long start = System.currentTimeMillis();
String a = "";
for (int i=0; i<100000; i++) {
a += "a";
}
long end = System.currentTimeMillis();
System.out.println("method01 used time:" + (end - start) + "ms");
}
public static void method02() {
long start = System.currentTimeMillis();
StringBuilder a = new StringBuilder("");
for (int i=0; i<100000; i++) {
a.append("a");
}
long end = System.currentTimeMillis();
System.out.println("method01 used time:" + (end - start) + "ms");
}
}
結(jié)果如下:
method01 used time:3591ms
method01 used time:2ms
例三
這個(gè)例子我們直接上代碼,區(qū)別很微小坐桩,就是在定義sum
的時(shí)候method01
使用了包裝類型尺棋,method02
則使用了基本類型。例子實(shí)現(xiàn)的是求所有int
正值的和绵跷。
public class Test03 {
public static void main(String[] args) {
method01();
method02();
}
public static void method01() {
long start = System.currentTimeMillis();
Long sum = 0L;
for (long i=0; i< Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
long end = System.currentTimeMillis();
System.out.println("method1 time used:" + (end - start) + "ms");
}
public static void method02() {
long start = System.currentTimeMillis();
long sum = 0L;
for (long i=0; i< Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
long end = System.currentTimeMillis();
System.out.println("method2 time used:" + (end - start) + "ms");
}
}
得到的結(jié)果是:
2305843005992468481
method1 time used:6170ms
2305843005992468481
method2 time used:633ms
可以看到細(xì)微的區(qū)別結(jié)果的差距還是蠻大的膘螟,所以我們要優(yōu)先使用基本類型而不是裝箱基本類型成福,要當(dāng)心無(wú)意識(shí)的自動(dòng)裝箱勒魔。
最終我們得到的結(jié)論是當(dāng)你應(yīng)該重用現(xiàn)有對(duì)象時(shí)舞终,請(qǐng)不要?jiǎng)?chuàng)建新的對(duì)象
峭沦。