第五章 初始化与清理(下)

来源:互联网 发布:oa数据库 编辑:程序博客网 时间:2024/05/16 12:10
                              第五章 初始化与清理
         现在总结的东西很多都需要用代码来帮助理解了,所以会有大量的测试代码,不过这中方式非常有用,如果认真敲过一遍之后,并且将这些代码弄清楚了,我相信你一定会对书中描述的内容有一个更清楚的认识。我是在eclipse工具上进行测试的,这里边的代码可以之间粘贴运行,不过对于程序员来说还是自己敲一遍吧,效果会更好。

5.5  清理 : 终结处理和垃圾回收
      程序员都了解初始化的重要性,但常常会忘记同样也重要的清理工作。Java有垃圾回收器负责回收无用对象占据的内存资源。但是,垃圾回收器只知道释放那些经过new分配的内存,如果你的对象(并非使用new)获得了一块“特殊”的内存区域,则垃圾回收器就不知道该如何释放这块“特殊”内存。为了应对这种情况,Java允许在类中定义一个名为finalize()的方法。这个方法的工作原理:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。所以要是你打算用finalize(),就能在垃圾回收时刻做一些重要的清理工作。
      注意:在Java中   
               1、对象可能不被垃圾回收。
               2、垃圾回收并不等于“析构”。(析构是在c++里出现的一个概念,就是在c++中要销毁对象必须使用析构函数)
5.5.1 finalize()的用途何在
        这里需要记住第三点:
        3、垃圾回收只与内存有关
          也就是说,使用垃圾回收器的唯一原因是为了回收程序不再使用的内存。所以对于与垃圾回收相关的任何行为来说(尤其是finalize()方法),它们也必须同内存及其回收有关。
5.5.2  你必须实施清理
        要清理一个对象,用户必须在需要清理的时刻调用执行清理动作的方法。无论是“垃圾回收”还是“终结”,都不保证一定会发生。如果Java虚拟机(JVM)并未面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存的。
5.5.3  终结条件
        通常,不能指望finalize(),必须创建其他的“清理”方法,并且明确地调用他们。
     class Book{
     boolean checkedOut = false;
     Book(boolean checkOut){
          checkedOut=checkOut;
     }
     void checkIn(){
          checkedOut=false;
     }
     protected void finalize(){
          if(checkedOut){
               System.out.println("error : checked out");
               try {
                    super.finalize();
               } catch (Throwable e) {
                    System.out.println("Throwable");
                    e.printStackTrace();
               }
          }
     }
}
public class TerminationCondition {
     public static void main(String[] args) {

          Book novel = new Book(true);
          novel.checkIn();
          new Book(true);
          System.gc();
     }

}
运行结果:error : checked out
因为在main()方法中,由于程序员错误,有一本书未被签入。要是没有finalize()来验证终结条件,将很难发现这种缺陷。
5.5.4  垃圾回收器如何工作

5.6  成员初始化
     Java尽力保证:所有变量在使用前都能得到恰当的初始化。对于方法的局部变量,Java以编译时错误的形式来贯彻这种保证。
     例如:我们定义成员变量的时候并没有给它们赋值,但是编译器会给它们初始化默认值,比如 int i;在编译的时候初始值就是0。但是在方法中就不行了:  void f(){
             int i;
             i++;     //错误,i没有被初始化
}
5.6.1  指定初始化
       如果想为某个变量赋初值,在基本数据类型中可以直接赋值。例如:int i=1;  char ch='x' ; boolean bool=true; 
       如果是其他类型的对象则可以创建一个对象来初始化:Depth d=new Depth();
       当然也可以通过调用方法来初始化:int i=f();

5.7  构造器初始化
      public class Counter {
     int i;
     public Counter() {
          i=7;
     }
该程序中i首先会被置零,然后变成7。
5.7.1  初始化顺序
      在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散步与方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
5.7.2  静态数据的初始化
       无论创建多少个对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初值;如果它是一个对象的引用,那么它的默认初始化值就是null。
class Bowl{
     Bowl(int marker){
          System.out.println("Bow1("+marker+")");
     }
     void f1(int marker){
          System.out.println("f1("+marker+")");
     }
}
class Table{
     static Bowl bowl1= new Bowl(1);
     Table(){
          System.out.println("Table()");
          bowl2.f1(1);
     }
     void f2(int marker){
          System.out.println("f2("+marker+")");
     }
     static Bowl bowl2=new Bowl(2);
}
class Cupboard{
     Bowl bowl3=new Bowl(3);
     static Bowl bowl4=new Bowl(4);
     Cupboard(){
          System.out.println("Cupboard");
          bowl4.f1(2);
     }
     void f3(int marker){
          System.out.println("f3("+marker+")");
     }
     static Bowl bowl5=new Bowl(5);
}
public class StaticInitialization {

     public static void main(String[] args) {
          System.out.println("createing new cupboard in main");
          new Cupboard();
          System.out.println("createing new cupboard in main");
          new Cupboard();
          table.f2(1);
          cupboard.f3(1);
     }
     static Table table=new Table();
     static Cupboard cupboard=new Cupboard();

}
运行结果:
Bow1(1)
Bow1(2)
Table()
f1(1)
Bow1(4)
Bow1(5)
Bow1(3)
Cupboard
f1(2)
createing new cupboard in main
Bow1(3)
Cupboard
f1(2)
createing new cupboard in main
Bow1(3)
Cupboard
f1(2)
f2(1)
f3(1)

由运行结果可以发现:初始化的顺序是先对静态对象(前提是得有对象被初始化时才会进行,就是说静态初始化只有在必要时刻才会进行),而后是“非静态”对象,然后才是构造器。
5.7.3  显式的静态初始化
       Java允许将多个静态初始化动作组织成一个特殊的“静态子句”(有时也叫做“静态块”)。
     class Cup{
     Cup(int marker){
          System.out.println("cup("+marker+")");
     }
     void f(int marker){
          System.out.println("f("+marker+")");
     }
}
class Cups{
     static Cup cup1;
     static Cup cup2;
     static{
          cup1=new Cup(1);
          cup2=new Cup(2);
     }
     Cups(){
          System.out.println("cups ()");
     }
}
public class Explicitstatic {

     public static void main(String[] args) {
          System.out.println("inside main");
          Cups.cup1.f(99);
     }
//     static Cups cups1=new Cups();
}
运行结果:
inside main
cup(1)
cup(2)
f(99)

      静态块跟静态初始化一样也只执行一次,当首次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员(即便从未生成过那个类的对象)。就会被执行。
5.7.4  非静态实例初始化
      Java中也有被称为实例初始化的类似语法,用来初始化每一个对象的非静态变量。例如:
      class Mug{
     Mug(int marker){
          System.out.println("Mug("+marker+")");
     }
     void f(int marker){
          System.out.println("f("+marker+")");
     }
}
public class Mugs {
     Mug mug1;
     Mug mug2;
     {
          mug1=new Mug(1);
          mug2=new Mug(2);
          System.out.println("mug1 & mug2 initialized");
     }
     Mugs(){
          System.out.println("Mugs()");
     }
     Mugs(int i){
          System.out.println("Mugs(int)");
     }

     public static void main(String[] args) {
          System.out.println("inside main()");
          new Mugs();
          System.out.println("new Mugs() completed");
          new Mugs(1);
          System.out.println("new Mugs(1) completed");

     }

}
运行结果:
inside main()
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs()
new Mugs() completed
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs(int)
new Mugs(1) completed

从以上代码可以看出少了static关键字,所以会重复执行。

5.8  数组的初始化
     数组的初始化有几种方法:
     第一种:int [] a={a,b,c}   这种方式是你明确知道要初始化多少个数据,这种形式很有用,但缺点也很明显,就是更加受限。
     第二种 : int [] a = new a [n]   这种形式可以解决你不知道具体要多少数据的难题,使用时可以根据情况而定。
      
5.9  枚举类型
      在Java SE5中添加了一个看似很小的特性,即enum关键字,它使得我们在需要群组并使用枚举类型集时,可以很方便的处理。在很大程度上,可以将enum当作其他任何类来处理,事实上enum确实是类,并且具有自己的方法。enum有一个特别实用的特性,即ta3可以在switch语句内使用;
     enum Spiciness{
     NOT, MILD, MEDIUM, HOT, FLAMING
}
public class Burrito {
     Spiciness degree;
     public Burrito(Spiciness degree){
          this.degree=degree;
     }
     public void describe(){
          System.out.print("this burrito is ");
          switch (degree) {
          case NOT:
               System.out.println("not spicy at all");
               break;
          case MILD:
          case MEDIUM:
               System.out.println("A little hot");
               break;
          case HOT:
          case FLAMING:
          default:
               System.out.println("maybe too hot");
               break;
          }
     }
     public static void main(String[] args) {
          Burrito
          plain = new Burrito(Spiciness.NOT),
          greenChile=new Burrito(Spiciness.MEDIUM),
          jalapeno=new Burrito(Spiciness.HOT);
         
          plain.describe();
          greenChile.describe();
          jalapeno.describe();
          
     }

}
运行结果:
this burrito is not spicy at all
this burrito is A little hot
this burrito is maybe too hot
0 0
原创粉丝点击