回顾Java编程思想篇(二)
4、销毁对象
Java中不需要程序员自己去销毁对象,这是为什么呢?
在C++中,对于变量及对象生命周期的维护占据了大量的编程时间,因为程序员需要知道变量存活的时间,以便在用完之后能把它销毁,不然会占满内存空间,阻塞程序。因此Java在设计时杜绝了这一问题。那么Java是怎么做的呢,看下面的介绍。
4.1、变量作用域
作用域决定了定义在其内的变量名的可见性和生命周期。在Java中作用域由花括号的位置决定。我们先看一下变量的作用域,例如:
package com.fei.test; public class TestJava { public static void main(String[] args) { int x = 10; //仅x变量可用 { int y =20; System.out.println("x = " + x); x = 12; System.out.println("y = " + y); //x与y都可用 } System.out.println("x = " + x); //x可用,y超出了作用域范围 } }
打印出的结果是:
x = 10
y = 20
x = 12
这里分为两个作用域,x定义在一级作用域里,y定义在二级作用域里。从结果可以看出二级作用域中对x变量重新赋值后,会覆盖上一级作用域的x变量的值。
Java中,在两个作用域的变量名称是不能一样的,比如:
int x = 10; { int y =20; int x = 12;//编译器会提示错误 }
因为Java设计者认为这样做会导致程序混乱,而在C++中这样是合法的。例如:
#include "stdafx.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { int x = 10; { int x = 12; cout<<"x = "<<x<<'\n'; //这个作用域的x变量与上级作用域的x变量虽然名字相同, //但不是同一个变量。 } cout<<"x = "<<x<<'\n'; cin>>x; return 0; }
打印出的结果是:
x = 12;
x = 10;
从结果看出,x变量在二级作用域重新定义后,变成另外一个x变量,它会替换一级作用域的x变量,但它的作用域只在二级作用域内有效,在一级作用域中定义的x变量在这样的情况下在二级作用域是起不了作用的。因此这样很容易搞不清楚x变量的使用情况,Java在设计时避免了这一情况。
4.2 对象作用域
下面看一下对象的作用域。
Java对象与基本类型的变量有不一样的生命周期。当用new创建一个对象后,它可以存活于作用域之外。先看一段代码:
package com.fei.test; public class TestJava { public static void main(String[] args) { String s1 = new String("abc"); { System.out.println("s1 = " + s1); //s1可用 String s2 = new String("efg"); System.out.println("s2 = " + s2); //s2可用 } System.out.println("s1 = " + s1); System.out.println("s2 = " + s2); //编译错误,s2超出了其作用域。 } }
从代码看起来,s1对象s2对象好像和变量是一样的生命周期,其实不然,这里只是指的s1引用和s2引用的生命周期。s2引用在二级作用域终点就消失了,因此在一级作用域里就不可用了。但是,s2指向的String对象仍然存在于内存中。如果要在其他作用域使用s2指向的对象怎么办呢?那么可以使用传递和复制对象引用的方式来使用对象。
这样会出现一个问题,每次新建的对象会一直保留在内存中,不是要把内存占满吗?不用担心,Java使用了一个叫做垃圾回收机制的功能,用来监视用new创建的所有对象,一旦发现那些不会再被引用的对象,便释放这些对象的内存空间,以便供其他新的对象使用。
因此新建的对象有两个去处,一个是通过传递和复制引用的方式供别的作用域使用,一个是被垃圾回收器销毁。