扎实的java功底系列(Effective java)5
避免创建不必要的对象
首先,由一个例子引出这个问题:
//首先这个是调用正常的String构造方法 String str = new String("test string"); //下面这个是一个String的自动装箱,过程就是把String类型的字符串首先构造成一个String类的对象,再赋给str String str = "test string 2";
上面这个放在循环中,每次都会构造一个新的对象,而下面这个则会重用这个对象。比如说:
1 String string = "hei goodboy"; 2 String string2 = "hei goodboy"; 3 System.out.println(string == string2); 4 System.out.println(string.equals(string2));
上面这段代码输出的结果是:true true
那么可以看出string 和 string2引用的是同一个对象。
String string = new String("hei goodboy"); String string2 = new String("hei goodboy"); System.out.println(string == string2); System.out.println(string.equals(string2));
这段代码的输出是:true false,== 比较的是两个对象的内容 而equals比较的是两个对象的引用是否相同,很明显,这里的两个string对象是不同的。
除了重用不可变的对象之外,我们也可以重用那些已知不会被修改的对象。还是用Car的例子改书上的,上代码:
package serviceprovider; import java.sql.Date; import java.util.Calendar; import java.util.TimeZone; public class Car { /** * 检验一辆车是否产于2013-2015年 */ private final Date birthdayDate = null; public boolean isBoomBetweenYear(){ Calendar gmtcal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtcal.set(2013, Calendar.JANUARY); Date startDate = (Date) gmtcal.getTime(); gmtcal.set(2015, Calendar.JANUARY); Date endDate = (Date) gmtcal.getTime(); return birthdayDate.compareTo(startDate)>=0 && birthdayDate.compareTo(endDate) <0; } }
上面这段代码每次调用isBoomBetweenYear的时候都要创建很多新的对象,比如gmtcal 、两个Date类型的变量,仔细观察,我们发现gmtcal对象在创建以后就可以一直使用同一个,不需要重新创建,故提出来,不放在方法中。
两个Date类型的变量也可以提出来。因此代码变成了:
package serviceprovider; import java.sql.Date; import java.util.Calendar; import java.util.TimeZone; public class Car { /** * 检验一辆车是否产于2013-2015年 */ // private final Date birthdayDate = null; // public boolean isBoomBetweenYear(){ // Calendar gmtcal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); // gmtcal.set(2013, Calendar.JANUARY); // Date startDate = (Date) gmtcal.getTime(); // gmtcal.set(2015, Calendar.JANUARY); // Date endDate = (Date) gmtcal.getTime(); // return birthdayDate.compareTo(startDate)>=0 && birthdayDate.compareTo(endDate) <0; // } private final Date birthdayDate = null; private static final Date STARTDATE; private static final Date ENDDATE; static { Calendar gmtcal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtcal.set(2013, Calendar.JANUARY); STARTDATE = (Date) gmtcal.getTime(); gmtcal.set(2015, Calendar.JANUARY); ENDDATE = (Date) gmtcal.getTime(); } public boolean isBoomBetweenYear(){ return birthdayDate.compareTo(STARTDATE)>=0 && birthdayDate.compareTo(ENDDATE) <0; } }
改进的代码只在类初始化的时候才创建一次Calendar、TimeZone、Date实例一次。
当你在自动装箱的时候,java会创建多余的对象。
public static void main(String[] args) { Long sum = 0L; for(long i = 0; i<Integer.MAX_VALUE; i++){ sum += i; } }
上面的代码能够正确运行但是在运行到 sum+=i的时候会有一个自动装箱的过程,会创建一个新的对象。下面我们验证一下:
package serviceprovider; import java.sql.Date; import java.util.Calendar; import java.util.TimeZone; public class Car { public static void main(String[] args) { Long sum = 0L; Long sum2 = sum; System.out.println(sum2 == sum); System.out.println(sum2.equals(sum)); /** * sum 和 sum2 无论是内容和引用都是一样的 */ for(long i = 0; i<3; i++){ sum += i; System.out.println(sum.equals(sum2)); System.out.println(sum == sum2); } } }
代码运行的结果是true true
true true
false false
false flase
也就是说在循环内的sum 由于自动装箱,引用改变了。当然在加上0的时候是不会改变引用对象的。

浙公网安备 33010602011771号