导致不必要的内存浪费。所以要在循环外去声明。
到底会不会产生多余的对象,自己测试程序如下:
测试对象:
package com.dao;
public class Student {
public static int num = 0;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private int age = 0;
public Student(String name, int age) {
this.name = name;
this.age = age;
++num;
}
// 打印名字10次
public void print() {
for (long i = 0; i < 10; ++i) {
System.out.print(getName());
}
System.out.println();
}
}
测试类:
package com;
import java.util.ArrayList;
import java.util.List;
import com.dao.Student;
public class TestForLoop {
public static void main(String[] args) {
// 每个for循环创建对象的个数
int count = 800000;
long ct = System.currentTimeMillis();
Student o1 = null;
for (int i = 0; i < count; ++i) {
o1 = new Student("ddd", 55);
o1.print();
}
long ctt1 = System.currentTimeMillis() - ct;
long ct1 = System.currentTimeMillis();
for (int i = 0; i < count; ++i) {
Student o2 = new Student("ggg", 56);
o2.print();
}
ct1 = System.currentTimeMillis() - ct1;
List<Student> list = new ArrayList<Student>();
for (int i = 0; i < count; ++i) {
list.add(new Student("tt", 120));
}
long ct3 = System.currentTimeMillis();
for (Object o : list) {
Student o3 = (Student) o;
o3.print();
}
ct3 = System.currentTimeMillis() - ct3;
System.out.println("外部声明对象花费的调用时间:" + ctt1);
System.out.println("内部声明对象花费的调用时间:" + (ct1));
System.out.println("for each 调用话费的时间:" + ct3);
System.out.println("本次总共创建的student对象的个数:" + Student.num);
}
}
测试结果如下:
外部声明对象花费的调用时间:26324
内部声明对象花费的调用时间:26580
for each 调用话费的时间:26478
本次总共创建的student对象的个数:2400000
程序跑了5次统计记过
通过测试发现:每个循环体循环80万次,每个for循环体都是创建了80万个对象;整好240万个对象 for循环中用到变量在循环体中声明并不会创建多余的对象。
性能方面:用jdk1.5支持的的for each稍微好一点,放在内部循环声明变量的性能最差,但是差别也不是很大。
究竟哪种写法更好:我认为依据的一个重要原则是:将将局部变量作用域最小化。所以,for each最好,变量放到循环体的次之,变量放到循环体外边的最不提倡。
采用for each最好,这个也是在Effective java推荐的,因为它简单,定义的变量最少,只定义了一个变量,而且最重要的一个原则是它将局部变量作用域最小化。
变量声明放到循环外,无疑扩大了它的作用域,甚至有可能在下面的程序中被误用到机率大大提升。这在无论是过程化的编程还是面向对象的都是不被提倡的。
推而广之,不管是方法还是语句块,你的程序应该尽可能隐藏自己的实现细节,这个在Effective java 中有下面一段话:
“将局部变量作用域最小化”的方法是小而集中。如果把两个操作(activity)合并到同一个方法中,与其中的一个操作相关的局部变量就有可能会出现在执行另一个操作的代码的范围之内。为了防止这种情况发生,只要把这个方法分成两个,每个方法各执行一个操作。
节选自《Effective Java 中文版》第二版 第8章 通用程序设计 181页
也就是说方法的功能定义必须是单一且明确的,方法不能干了一件事情又干另一件事情。所以,上千行 的方法体它的功能定义肯定不是明确的,绝对是要被分拆的。
后记:后来有人提出,for循环中的变量o1,o2,o3被创建了多个。到底是不是创建多个o1,o2,o3?
在《深入理解Java虚拟机:Java高级特性与最佳实践》第二版 第二章:Java内存区域与内存溢出异常 第40页有下面的一段话:
局部变量表中存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、fload、long、double)、对象引用(reference)类型,。。。。。。
。。。。。。局部变量表所需的内存空间在编译期间完成分配,。。。。。。
上面两段话说明对象的引用的内存空间的分配是在编译期间由编译期扫描所有的变量并完成内存空间的分配。
以上测试软硬件配置:
Java版本信息:
java version "1.6.0_10-rc2"
Java(TM) SE Runtime Environment (build 1.6.0_10-rc2-b32)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)
机器配置:
CPU:Intel(R) Core(TM) i5-4200U CPU @1.60GHz 2.30GHz
内存:4.00G
操作系统:Win7 64位