JAVA基础学习篇----《thinking in java》第四章:初始化与清理

构造函数重载: 重载三要素(参数数量、参数类型、参数的排列顺序)。
基本数据类型的重载: 如果实参比形参的类型小,数据会先提升,如果实参比形参大,那么要先进行强制类型转换。
返回值类型不是重载的要素: 理解之一是,构造函数要实现重载,但构造函数无返回值。另外调用函数的时候可以没有返回值类型。

this关键词的使用:

1、this只能用于方法内部,它负责返回调用这个方法的对象的引用。你可以把this对象的引用当成任何对象的引用。

2、this用于在构造函数中调用其他构造函数,但只能调用一个,且调用的代码应放在程序最前面,否则编译器会报错。

3、this.s=s当类的数据成员与类的方法的参数同名时,使用this.s=s消除歧义。

static的含义:

它的意思是,这个方法没有this,你不能在static方法里调用非static的方法,但你却可以不通过对象,直接调用static方法。类的static方法只能访问其它static方法static成员。

垃圾回收:
java提供finalize()方法用于垃圾回收器回收前执行方法中的代码进行非new所创建内存的清理。你可以自己定义类的finalize()方法。不过要注意java对象并不总是会被回收的。它不象C++一样提供析构函数,可做到总是回收。java垃圾回收特点:
1、对象不一定会被垃圾回收器回收;
2、垃圾回收不是析构;
3、你可以自己写方法时行垃圾回收;
4、垃圾回收只与内存有关;
5、垃圾回收和finalize()都是靠不住的,只要jvm还没到快要耗尽内存的地步,它是不会浪费时间来回收垃圾以恢复内存的。

初始化的顺序: 初始化的顺序是由变量在类的定义里面的顺序所决定的 变量的定义可能会分散在类定义的各个地方并且与方法的定义相互交错,但是变量的初始化会先于任何方法,甚至是构造函数的调用。以下为例:
    class Tag{
    Tag(int marker){
        System.out.println("Tag("+marker+")");
    }
}
class Card{
    Tag t1 = new Tag(1);
    Card(){
        System.out.println("Card()");
        t3 = new Tag(22);
    }
    Tag t2 = new Tag(2);
    void f(){
        System.out.println("f()");
    }
    Tag t3 = new Tag(3);
}
public class Clean {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Card t = new Card();
        t.f();

    }

}
输出结果为:
Tag(1)
Tag(2)
Tag(3)
Card()
Tag(22)
f()

Static数据的初始化(注意结合代码调试理解):

package com.initialization.order;
class Bowl {
   Bowl(){
    System.out.println("Bowl(9)");
   }
   Bowl(int marker) {
     System.out.println("Bowl(" + marker + ")");
   }
    static Bowl b6 = new Bowl(6);
    static Bowl b9 = new Bowl();
    
    void f(int marker) {
     System.out.println("f(" + marker + ")");
   }
 }

class Table {
  static Bowl b1 = new Bowl(1);
  Table() {
    System.out.println("Table()");
    b2.f(1);
  }
  void f2(int marker) {
    System.out.println("f2(" + marker + ")");
  }
  static Bowl b2 = new Bowl(2);
}
class Cupboard {
  Bowl b3 = new Bowl(3); 
  Bowl b10 = new Bowl(); 
  static Bowl b4 = new Bowl(4);
  Cupboard() {
    System.out.println("Cupboard()");
    b4.f(2);
  }
  void f3(int marker) {
    System.out.println("f3(" + marker + ")");
  }
  static Bowl b5 = new Bowl(5);
}

public class StaticInitialization {
 //static Bowl b7 = new Bowl(7);                     //----------(1)
  public static void main(String[] args) {
    System.out.println(
      "Creating new Cupboard() in main");
    new Cupboard();
    System.out.println(
      "Creating new Cupboard() in main");
    new Cupboard();
    //t2.f2(1);                                 //--------------(2)
    //t3.f3(1);                                 //---------------(3)
  }
  //static Bowl b8 = new Bowl(8);  //----------------(4)
  //static Table t2 = new Table();   //----------------(5)
  //static Cupboard t3 = new Cupboard();  //---------(6)
} ///:~

调试以上代码,总结出以下结论:

一、初始化的过程:总体来说顺序为:static初始化->非static初始化->执行构造函数;
二、代码分析一:对现有代码执行结果如下:

Creating new Cupboard() in main
Bowl(6)
Bowl(9)
Bowl(4)
Bowl(5)
Bowl(3)
Bowl(9)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Bowl(9)
Cupboard()
f(2)
执行过程:
         1、java解释器寻找public class类,加载StaticInitialization 类;
         2、寻找StaticInitialization 类中的static定义代码段;这里因为(1)、(4)、(5)、(6)均加了注释,所以StaticInitialization 中没有static需要初始化;

         3、进入main函数中执行代码输出Creating new Cupboard() in main
         4、继续执行new Cupboard();,注意初始化的顺序是static初始化->非static初始化->执行构造函数; 所以加载类Cupboard后,首先寻找Cupboard类中的static代码段
发现static段 是:  static Bowl b4 = new Bowl(4); static Bowl b5 = new Bowl(5);
同时发现有非static段 是: Bowl b3 = new Bowl(3);   Bowl b10 = new Bowl();  
按顺序先执行:static Bowl b4 = new Bowl(4); 初始化,因为定义的是Bowl类的实例,所以先加载Bowl类 ,进入Bowl类发现又有static 代码段static Bowl b6 = new Bowl(6);
    static Bowl b9 = new Bowl();然而们知道初始化static Bowl b4 = new Bowl(4); 需要调用Bowl 的构造函数,但调用构造函数之前必须将该类需要初始化的部分先进行初始化,所以执行到这里就要先进行Bowl类中的static代码段的初始化,之后才能调用构造函数Bowl(int marker) 为static Bowl b4 = new Bowl(4); 进行初始化。 于是b6,b9分别调用构造函数Bowl(int marker),Bowl(),输出Bowl(6),Bowl(9), 完了之后,b4调用构造函数Bowl(int marker)输出 Bowl(4), b4初始化结束,返回Cupboard类继续执行,初始化b5,输出 Bowl(5) ,此时Cupboard类中static部分初始化完,接下来对非static部分初始化,即对b3和b10初始化, 一样的方法,加载Bowl类,发现static字段在上面已经初始化,所以这里直接调用Bowl类的构造函数,输出Bowl(3),Bowl(9)。 至此Cupboard类中需要初始化的部分已经初始化完了,所以放心大胆的调用Cupboard类的构造函数 ,为main函数中代码完成new Cupboard();的实现,输出Cupboard(),f(2)。 程序执行返回到main函数,输出:Creating new Cupboard() in main, 代码new Cupboard();又一次出现,这里实际上是想演示static只会初始化一次 ,而非static只要创建了对象或调用了成员、成员函数,会进行第二次初始化 ,于是可以看到输出结果并没有再 输出Bowl(6)、Bowl(9)、Bowl(4)、Bowl(5),而是输出:Bowl(3)、Bowl(9)、Cupboard()、f(2)。
5、取消注释(1)、(4),发现结果如下:
Bowl(6)
Bowl(9)
Bowl(7)
Bowl(8)
Creating new Cupboard() in main
Bowl(4)
Bowl(5)
Bowl(3)
Bowl(9)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Bowl(9)
Cupboard()
f(2)
可以看出输出了Bowl(7)、Bowl(8),这说明在main()函数执行之前,程序要先对StaticInitialization进行检查,如果有static部分,则先初始化。
6、再取消注释(2)、(5)输出结果为:
Bowl(6)
Bowl(9)
Bowl(7)
Bowl(8)
Bowl(1)
Bowl(2)
Table()
f(1)
Creating new Cupboard() in main
Bowl(4)
Bowl(5)
Bowl(3)
Bowl(9)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Bowl(9)
Cupboard()
f(2)
f2(1)
在前面的基础上又输出了Bowl(1)、Bowl(2)、Table()、f(1)。然而我们看到当没有代码
static Table t2 = new Table();的时候Table类中的static部分没有被初始化,这说明什么?
static初始化只有在必要的时候才会进行。只有在创建了第一个Table对象之后才会进行初始化。

总结如下: 初始化顺序为:加载public StaticInitialization类->初始化static->加载类Cupboard->初始化static->加载类Bowl->初始化static->执行Bowl类构造函数->初始化Cupboard类非static->调用Bowl类构造函数执行->调用Cupboard类构造函数执行->返回StaticInitialization类.

 

上例中只涉及组合关系的类的初始化顺序,下文中对含有继承关系的初始化过程说明:

http://blog.csdn.net/luweifeng1983/archive/2009/11/02/4758730.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值