Object s;
for(int i=0;i<10;i++)
{
s = new String("sss");
}
for(int i=0;i<10;i++)
{
Object s = new String("sss");
}一种是循环外定义变量,一种是循环内定义变量,这两种方式到底有什么概念的性能差异循环外定义变量可以避免在循环内一次次的声明实例引用,但是要等到方法结束才释放最后指向的实例。也就是说在方法结束前总有一个实例是不被回收的。循环内定义变量可以在每一次循环结束通知GC释放实例两种写法的对实例的回收次数都是一样的,关键是回收时机和引用的声明次数。
for(int i=0;i<10;i++)
{
s = new String("sss");
}
for(int i=0;i<10;i++)
{
Object s = new String("sss");
}一种是循环外定义变量,一种是循环内定义变量,这两种方式到底有什么概念的性能差异循环外定义变量可以避免在循环内一次次的声明实例引用,但是要等到方法结束才释放最后指向的实例。也就是说在方法结束前总有一个实例是不被回收的。循环内定义变量可以在每一次循环结束通知GC释放实例两种写法的对实例的回收次数都是一样的,关键是回收时机和引用的声明次数。
for (;;) {
Object ...
}
在乎的不是GC不GC的,而在乎于隔离两次循环之间变量,使之不会冲突或者彼此干涉
{
public static void f1()
{
Object s;
for(int i=0;i<10;i++)
{
s = new String("sss");
}
} public static void f2()
{
for(int i=0;i<10;i++)
{
Object s = new String("sss");
}
}
}
以上两个方法编译出来的字节码完全一样,都是public static void f1();
Code:
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 24
8: new #2; //class java/lang/String
11: dup
12: ldc #3; //String sss
14: invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V
17: astore_0
18: iinc 1, 1
21: goto 2
24: returnpublic static void f2();
Code:
0: iconst_0
1: istore_0
2: iload_0
3: bipush 10
5: if_icmpge 24
8: new #2; //class java/lang/String
11: dup
12: ldc #3; //String sss
14: invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V
17: astore_1
18: iinc 0, 1
21: goto 2
24: return}
相反变量定义在内层更能及时的被回收,每次循环结束即可以让GC回收。
首先要与己方便,然后才能与人方便。需要在循环外面用到的,那就放在外面,否则一律应放入循环体内。
有时候,刻意优化,反而效果更差。比如,我经常看到
String sql =
" SELECT A.X X, " +
" B.Y Y, " +
......
" FROM TBL_A A, " +
" TBL_B B " +
" WHERE ....... "; // 二三十行,近千个静态字符
很多人只知道拼接String应当用StringBuffer,比如
StringBuffer buff = new StringBuffer();
buff.append(" SELECT A.X X, ");
buff.append(" ...... ");
....
String sql = buff.toString();
自以为优化了代码,却不知道这样子内存开销更大,效率更差。因为中间有几个append就出现几个中间的String,同时StringBuffer的capacity还要从默认的16,扩容好几次才能上千。而用+,由于中间全是静态的,编译器会自动优化成一个String。同样,变量声明在for内外,对于GC来说,根本没有太大区别。先不论gc时机和具体回收的堆内容的不确定性,就光看栈引用和堆对象的关系而言,两种写法都只会新创建N个堆对象,同时,任意时刻,都只有一个栈引用一个堆对象。除了循环之后,最后一个有些许差别外,其余,根本看不出任何在“性能”上,某种写法压倒另外一种写法的理由。
Object o;
for(;;){
o=new Object();
}2:
for(;;){
Object o=new Object();
}第一种方法变量o只生成一次
第二种方法,每次都回生成变量o虽然没有创建对象,但生成一个变量,系统仍然要分配内存空间的,所以第一种效率高但是现在的编译器都是带优化的,编译的时候一优化就一样了.无所谓的.
for(int i=0;i<10;i++)
{
s = new String("sss");
}
for(int i=0;i<10;i++)
{
Object s = new String("sss");
}放在外面是N个s,一一对应地引用N个String实例;
放在里面是1个s,一一引用N个String实例;
放在外面,创建String实例的过程一样,回收的过程不详(java我不懂)
放在里面,创建String实例的过程一样,回收的过程不详(java我不懂)
放在里面外面,只是多个s和一个s的不同,在罗辑上是这样,实际过程,不详,因为我不懂,我真的不懂.
比如你要用个循环把一个对象添加到list,那么有时候就不得不定义了
放在里面是1个s,一一引用N个String实例;
??????????????
2.在循环体外声明一个只有循环体内才使用的变量是一个不良习惯,这是典型老式C语言的编程风格,就像在C语言中滥用全局变量一样,这样会扰乱上下文变量的定义和语义,造成程序本身的不可读性。
3.非持久性状态变量声明尽量局部化,这是模块化和面向对象思想的一般准则。
2、推荐“不要在循环体内定义变量”是一条广泛和一般的准则。如果是一个完全正确的程序员,可以违反这个规则。正如同有人用汇编写大型系统。但毕竟是少数人员,出错的概率也太大。对于一般人,清晰的变量定义、变量内存申请、变量回收是非常需要考虑的。
3、循环体内定义、回收是可以的,但是面对复杂的程序,过多的BREAK和CONTINUE, 再加上与变量定义、变量内存申请、变量回收搅在一起无疑会增加程序的复杂度。
4、从普遍意义上来说,“不要在循环体内定义变量”是一条工程化和软件化的规则,当然高手不受此限制。
Object o;
for(;;){
o=new Object();
}2:
for(;;){
Object o=new Object();
}第一种方法变量o只生成一次
第二种方法,每次都回生成变量o^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
应该不是吧 记的学C的时候 书上讲的:
for( ...)
{
int i=5; //只在第一次循环才声明(C专家编程里的,就是书皮有条很丑的鱼那本)
}
{
int i=5; //只在第一次循环才声明
}试想一下,如果想当然的认为是每次循环都会定义,那么把这个循环展开就会是
int i=5;
int i=5;
......
显示是不能为编译器接受的。
void main()
{
for(int i=0;i<5;i++)
{
int* num = new int;
}
}
可以发现每次循环时 &num是同一个值,指针本身这个32位整数值是不变的。
2NEW的用途,我听别人说好象NEW出来的东西需要自己手工回收的,可能系统也可以自动回收,但不管怎么样,每NEW一次就会新建一个对象,然后改变引用转变到新的变量的地址上,然后原来的对象没有被回收,只有在循环结束后才被统一回收,那么那么在循环期间循环次数越多,生成的对象也就越多,这样会占用系统资源,导致速度下降。
另外java编译器是有一定的优化功能的,不过一方面并不能叫准他的优化规则,另外一方面过分依赖编译器的优化能力也是一个很危险的事情。
一般的情况是:
Object o = null;// 假设list里面有几个对象;
for (int i = 0; i < list.size(); i++) {
o = (Object)list.get(i);
}
如果定义到里面每次循环结束的时候都要把o(Object)完全回收;不同的虚拟机回收机制不同,这样有可能影响到代码的运行效率。而定义到外面,每次循环结束不需要调用回收机制从而提高运行效率。一般比较大的程序,比如银行,保险业数据比较庞大,即使是一点点的效率提高也会被非常明显的表现出来。
无论是在循环内还是循环外定义,只要是结束当前循环后,前一个变量就成了游离的对象,可以被GC清理掉的。
=============
非也!OOP提倡封装,把局部使用的变量尽可能放到小的范围中是一种美德,而不会给阅读和维护带来麻烦。2、从直觉上的代码效率(既然很多朋友这么愿意讨论这个问题,干嘛不实际测试一下,纸上谈兵百无一用。我不测试,因为有时间还得做比这个重要的事)看,肯定循环体内反复定义是很差劲的,除非编译器在这方面作了优化,使其和在循环体外定义的结果是一样的,但那样也就没有讨论必要了。
==========
我认为就题目上面给出的代码,没有效率上的差别,即使有,也非常非常微弱,不足挂齿。
我从开始写程序就喜欢把一个函数过程中所有用到的变量声明语句写在执行语句前面(这点在DELPHI中有很好的体现。如同做菜的菜板,生熟应该分开,代码一团乱,不干不净,吃了有病),并加注释。后来看到关于代码规范的资料,也是这样说的。
============
其实规范也是相对而言的,我管理的项目中,都要求变量和注释放在用到的地方,很明显这比你翻屏幕来得方便些。
我想一定是某个人搞错了,可能想说的是“尽量不要在循环体内new对象”,这就很好理解了,因为这样会导致效率问题。