变量的作用域和生命周期

目前,我们使用的变量都是在main()方法的开始处声明的.然而Java允许变量在任何代码块声明.代码块定义了作用域(scope).因此,每次创建新额代码块时,就是在创建新的作用域.作用域决定了对于程序的其他部分哪些对象是可见的,还决定了这些对象的生命期.
其他大多数计算机语言都定义了两类基本的作用域:全局作用域和局部作用域.Java尽管也支持这种分类,但这不是Java作用域的追加分类方式.在Java中最重要的作用域是由类和方法定义的作用域.
方法定义的作用域从方法的左花括号开始.然而,如果方法有形参,那么这些形参也包含在方法的作用域之内.
做为一项基本原则,在作用域内声明的变量对于作用域之外定义的代码是不可见的.因此,当在作用域内声明一个变量时,就把这个变量局部化了,并且保护他在未授权的情况下不会被访问或修改.实际上,正式作用域规则提供了封装的基础.
作用域是可嵌套的,例如每次创建代码块都会创建新的,嵌套的作用域.当这种情况发生时,外层作用域包含内层作用域.这意味这在外层作用域定义的对象对于内层作用域中的代码是可见的;反之则不然,在内层作用域定义的对象对于外层作用域中的代码是不可见的.
我们用下面的程序来理解嵌套作用域的作用:
    public static void main(String args[])
    {
        int x = 10;
        if(x == 10)
        {
            int y = 20;
        }
        y = 100;
    }
变量x是在main()作用域开始处声明的,对于main()中其后的所有代码都是可访问的.在if代码块中声明了y.因为代码块定义作用域,所以y只对代码块中的其他代码是可见的.因为y对代码块以外的代码是不可见的,所以y=100会产生错误:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
    y cannot be resolved to a variable

    at javaTest.test.main(test.java:13)
在代码块的任何位置都可以声明变量,而变量只有被声明后才有效.因此,如果在某个方法的开始处定义一个变量,那么他对于方法中的所有代码都是有效的.相反,如果在代码块的结尾处声明了一个变量,那么他对于方法中的所有代码都是有效的.相反,如果在代码块的结尾处声明了一个变量,那么他是没有任何作用的,因为没有代码可以访问他.
此外,还有一个要点必须记住:变量在进入作用域时被创建,在离开作用域时被销毁.这就意味着变量一旦离开作用域就不会存储原来的值.因此,在方法调用之前,在方法中声明变量是无法保存其值的,而且在代码块中声明的变量在离开块时也将拾取他的值.因此变量的生命期被限制在作用域内.
如果变量声明包含初始化值,那么在每次进入声明他的代码块时都会被初始化:
    public static void main(String args[])
    {
        int i;
        for(i=0;i<3;i++)
        {
            int y = 1;
            System.out.println("y : "+y);
            y = 100;
            System.out.println("y is "+y+" now");
        }
    }
输出:
y : 1
y is 100 now
y : 1
y is 100 now
y : 1
y is 100 now
在每次进入内部for循环时,y都会被重新初始化为1,尽管y在后面被赋值为100,但该值无法保存.
Java作用域有一条规则可能会让你吃惊:尽管可以嵌套代码块,但是内部作用域中声明的变量不能与包含他的作用域中已经声明的变量同名:
    public static void main(String args[])
    {
        int i,y;
        for(i=0;i<3;i++)
        {
            int y = 1;
            System.out.println("y : "+y);
            y = 100;
            System.out.println("y is "+y+" now");
        }
    }
输出:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
    Duplicate local variable y

    at javaTest.test.main(test.java:11)
如果了解C/C++,就会知道内部作用域中声明的变量没有命名限制.因此在C/C++中,外部for循环的代码块中声明的y是完全有效的,这个声明会屏蔽外部的同名变量.Java的设计者感觉这个名称屏蔽(name hiding)容易导致编程错误,所以不在允许这么做.