【向ZangXT提问】循环中使用的局部变量,一般是在循环内部声明?还是在循环外部声明?

bigbro001 2009-01-01 10:38:53
例如下面这个打印一串数字的程序,需要在每个偶数后面标记一个星号,一种方法是把表示星号的变量mark声明在循环内部:

class Test
{
public static void main(String[] args)
{
for (int i = 1; i <= 10; i++)
{
String mark = "";
if (i % 2 == 0)
mark = "*";
System.out.println(i + mark);
}
}
}


另一种方法是,声明在循环外部:

class Test
{
public static void main(String[] args)
{
String mark;
for (int i = 1; i <= 10; i++)
{
mark = "";
if (i % 2 == 0)
mark = "*";
System.out.println(i + mark);
}
}
}


这两种方法,哪一种比较规范呢?或者说哪一种效率较高?
...全文
2218 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
LoveDelhi 2012-02-08
  • 打赏
  • 举报
回复
很显示,写在里面好.
其实随便写个函数,然后反汇编一下就知道了.

编译器比我们想象的聪明.
tyrhpx 2011-11-22
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 sxzlc 的回复:]

我前一段时间也遇到这个问题了。

最后认定,还是在里面定义好。


根据:

使变量的作用域尽量小些。
[/Quote]
支持……
sun0322 2011-09-04
  • 打赏
  • 举报
回复
我前一段时间也遇到这个问题了。

最后认定,还是在里面定义好。


根据:

使变量的作用域尽量小些。
autosky 2009-01-02
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 wang_wei2007 的回复:]
看了以后受益很多
如果两种写法对性能没有区别的话,那根据"尽量让局部变量的作用域小一些"的原则,是不是第一种写法更好一点呢?
[/Quote]
支持。
jerry313 2009-01-01
  • 打赏
  • 举报
回复
学习
wang_wei2007 2009-01-01
  • 打赏
  • 举报
回复
看了以后受益很多
如果两种写法对性能没有区别的话,那根据"尽量让局部变量的作用域小一些"的原则,是不是第一种写法更好一点呢?
kao331431214 2009-01-01
  • 打赏
  • 举报
回复
汗 点了一下写了半天的东西没了 o(>_<)o ~~

简单的说下
写在外部大家都明白
写在内部的时候
第一次循环
String mark;
编译器就建立了一个局部变量mark
又一次循环开始
编译器发现String mark;
又有一个局部变量mark
编译器就直接把这个局部变量mark拿来用

ZiSheng 2009-01-01
  • 打赏
  • 举报
回复
javap 强大,呵呵
ZangXT 2009-01-01
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 AeolusLau 的回复:]
引用 5 楼 ZangXT 的回复:
两个例子中实际分配的局部变量的数目是相同的。

不一样吧?
程序不知道这里会循环多少次,也不知道最后一次循环什么时候结束。如果定义在循环内,每次循环结束就会销毁这个变量。当下次循环开始的时候重新定义这个变量。
不过实际上这个问题是一个不必讨论的问题。在编译优化的时候,对于在循环内部定义的变量,编译器会自动把它提取到循环外部。也就是说就算是采用了lz的第一种写法,编译的时候…
[/Quote]
这里都是一些栈里的变量,怎么才叫分配,怎么才叫销毁?
使用javap -verbose 类名
可以查看一个方法中到底有几个局部变量,这个动手看一下就知道了。
风中舞者 2009-01-01
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 ZangXT 的回复:]
两个例子中实际分配的局部变量的数目是相同的。
[/Quote]
不一样吧?
程序不知道这里会循环多少次,也不知道最后一次循环什么时候结束。如果定义在循环内,每次循环结束就会销毁这个变量。当下次循环开始的时候重新定义这个变量。
不过实际上这个问题是一个不必讨论的问题。在编译优化的时候,对于在循环内部定义的变量,编译器会自动把它提取到循环外部。也就是说就算是采用了lz的第一种写法,编译的时候也会被编译成第二种写法。
bigbro001 2009-01-01
  • 打赏
  • 举报
回复
果不其然,刚刚反编译class文件后,上面两个程序生成的代码相同,都是:

import java.io.PrintStream;

class Test
{
Test()
{
}

public static void main(String args[])
{
for(int i = 1; i <= 10; i++)
{
String mark = "";
if(i % 2 == 0)
mark = "*";
System.out.println((new StringBuilder()).append(i).append(mark).toString());
}
}
}

也就是说如果按照最上面两种方法写代码,不管是写在外面还是写在里面,运行的时候都是没有区别的。

可是经过老紫竹上面的提示,如果把最上面第二种方法换一个写法,在声明变量的同时,也给他赋值:

class Test
{
public static void main(String[] args)
{
String mark = "";
for (int i = 1; i <= 10; i++)
{
mark = "";
if (i % 2 == 0)
mark = "*";
System.out.println(i + mark);
}
}
}

这样就可以达到老紫竹所说的“少生成许多的局部变量”这样的效果,这样的话,是不是更好一些呢?
ZangXT 2009-01-01
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 java2000_net 的回复:]
如果是我,绝对放在外面,至少可是少生成许多的局部变量。
[/Quote]
两个例子中实际分配的局部变量的数目是相同的。
ZangXT 2009-01-01
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 bigbro001 的回复:]
可是如果放到循环里面去了,那么每一次循环都要在栈中创建一个新的变量mark,走完一次后,该变量被销毁,然后下一次循环又重新创建一个,如此反复。。。
相比较,如果放在循环外面的话,新变量mark只是创建一次,以后的每次循环都只是赋不同的值而已,这样看来,放在外面会不会更节约呢?
[/Quote]
栈变量不是按你理解的这样分配和销毁的,你的两个例子中,编译器能检测到,这个方法一共用到了3个局部变量,一个是String[] args,一个是int i,一个是String mark,第二个例子中会重复使用String mark,方法开始执行的时候,这些内容就分配好了,都是3个局部变量的空间,并不是像你理解的那样用到一个分配一个。所以,两个例子本质上是相同的。
所以你的第一个例子中的 String mark = "";
和第二个例子中的mark = "";都是把""写到一个局部变量中去,效率上不会有差别。
bigbro001 2009-01-01
  • 打赏
  • 举报
回复
可是如果放到循环里面去了,那么每一次循环都要在栈中创建一个新的变量mark,走完一次后,该变量被销毁,然后下一次循环又重新创建一个,如此反复。。。
相比较,如果放在循环外面的话,新变量mark只是创建一次,以后的每次循环都只是赋不同的值而已,这样看来,放在外面会不会更节约呢?
老紫竹 2009-01-01
  • 打赏
  • 举报
回复
如果是我,绝对放在外面,至少可是少生成许多的局部变量。

虽然你这里用的是String的不可修改类。
ZangXT 2009-01-01
  • 打赏
  • 举报
回复
应该放在循环里面,尽量让局部变量的作用域小一些。仅仅在循环里面用的就尽量不要放到外面,在这个例子中是没有效率的差别的 。
whlxjq520 2009-01-01
  • 打赏
  • 举报
回复
受益匪浅啊!多谢了

62,630

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧