Java:避免创建不必要的对象
为了保证内存的有效利用,应该尽量重用对象而不是在每次需要的时候就创建一个新的对象。
比如,构造器在每次被调用的时候就构建一个新的对象,而静态工厂方法则从来不要求这样做(顺便说一句,如果要求对象只有一个实例,可以使用静态工厂方法;如果对象有多个/不定个参数,可以使用静态Builder方法构建)。
举例来说,新建字符串有两种方法:
法一: String s = new String("This is a string.");
法二: String s = "This is a String";
在法一中,使用构造器强制构建了一个新的对象,不管相同的字符串是否已经存在;
而在法二中,则会先查看是否已经存在了该String对象,如果存在,则返回已存在String的引用,而不会再新建String对象。
因此,如果在String已经存在的情况下,法一多创建了一个不必要的String实例。如果这是在一个循环中,则频繁调用会产生成千上万个不必要的String。
再举一个关于Long和long的例子。对于Long而言,相当于上例的法一,每次需要创建新的实例,而如果对象被定义为long,则相当于法二,对象可以重新使用。代码如下:
public static void main(String[] argv){
long startTime = System.currentTimeMillis();
System.out.println("Integer.MAX_VALUE:"+Integer.MAX_VALUE);
int result = 0;
for(long i=0;i<Integer.MAX_VALUE;i++){
result += i;
}
long endTime = System.currentTimeMillis();
System.out.println("Int Result:"+result+". Total Cost Time:"+(endTime - startTime));
startTime = endTime;
long sumlong2 = 0L;
for(long i=0L;i<Integer.MAX_VALUE;i++){
sumlong2 += i;
}
endTime = System.currentTimeMillis();
System.out.println("long-long Sum:"+sumlong2+". Total Cost Time:"+(endTime - startTime));
startTime = endTime;
long sumlong = 0L;
for(Long i=0L;i<Integer.MAX_VALUE;i++){
sumlong += i;
}
endTime = System.currentTimeMillis();
System.out.println("long-Long Sum:"+sumlong+". Total Cost Time:"+(endTime - startTime));
startTime = endTime;
Long sumLong1 = 0L;
for(long i=0L;i<Integer.MAX_VALUE;i++){
sumLong1 += i;
}
endTime = System.currentTimeMillis();
System.out.println("Long-long Sum:"+sumLong1+". Total Cost Time:"+(endTime - startTime));
startTime = endTime;
Long sumLong = 0L;
for(Long i=0L;i<Integer.MAX_VALUE;i++){
sumLong += i;
}
endTime = System.currentTimeMillis();
System.out.println("Long-Long Sum:"+sumLong+". Total Cost Time:"+(endTime - startTime));
}
在代码中,分别对sum和i使用Long和long来实现,查看最后耗费时间的区别(单位:ms)。另外,由于最后结果超过int,我们把int结果作为参照。
代码结果如下:
Integer.MAX_VALUE:2147483647
Int Result:1073741825. Total Cost Time:8172
long-long Sum:2305843005992468481. Total Cost Time:8687
long-Long Sum:2305843005992468481. Total Cost Time:59188
Long-long Sum:2305843005992468481. Total Cost Time:49000
Long-Long Sum:2305843005992468481. Total Cost Time:96500
可以看到,在sum和i均为long的时候,耗费时间是最小的,8600ms左右。i单独为Long比sum单独为Long耗费时间要多一些(为什么?猜测是对i的操作比对sum的操作多一些。不过除去创建耗时之外,消耗时间和操作次数是成正比的吗?)。而毫无争议的,sum和i都为Long的情况最耗时,约为100s。因此可以看出,将变量声明为long而非Long,可以有效的节省时间。
因此,要优先使用基本类型而不是装箱类型,要当心无意识的自动装箱。
参考资料:
Effective Java 中文版
