Thinking in Java:第五章 初始化与清理

5.1 用构造器确保初始化

      定义类时,若未定义构造函数,则系统会自动创建一个无参构造器(默认构造器),若已经定义了构造器,则不会自动创建无参构造器。

5.2 方法重载

      方法重载时,利用参数类型列表来区分方法,这里包括:参数类型、顺序、数量;

      涉及基本类型的重载时,基本类型能从一个“较小”的类型自动提升至一个“较大”的类型。也就是说方法接受较小的基本类型作为参数,如果传入的实际参数较大,就得通过类型转换来执行窄化转换。

5.3 默认构造器

5.4 this关键字

      为了能用简便、面向对象的语法来编写代码——即“发送消息给对象”,编译器做了一些幕后工作。它暗指把“所操作对象的引用”作为第一个参数传给类,所以如下的方法调用为:

//: initialization/BananaPeel.java

class Banana { void peel(int i) { /* ... */ } }

public class BananaPeel {
  public static void main(String[] args) {
    Banana a = new Banana(),
           b = new Banana();
    a.peel(1);
    b.peel(2);
  }
} ///:~
       此时,在编译器内部,两个方法的调用变为:

Banana.peel(a,1)

Banana.peel(b,2)

       另外,为一个类写了多个构造器,有时可能想在一个构造器中调用另一个构造器,以避免重复代码,此时使用this关键字。但是此时只能在构造器的开始处调用构造器,能且仅能调用一次。

5.5 清理:终结处理与垃圾回收

      java为类提供了finalize方法,该方法可以在垃圾回收时刻做一些重要的清理工作。

      对此,需要对垃圾回收做一个说明:对象可能不被垃圾回收;垃圾回收并不等于“析构”;垃圾回收只与内存有关。

     此时,我们可以知道,如果使用了java的native方法(如调用c++new了一个对象),此时如果不明确的调用C++ delete掉这个对象,则垃圾回收器是无法回收这个对象的。另外,你做的一些其他操作可能也无法清楚,比如你在屏幕上绘制了一个图像,如果不显示擦除,则该图像永远保留在屏幕上。

       如下是一个书籍借阅时签入的例子,所有的book对象在被当做垃圾回收前都应该被签入:

//: initialization/TerminationCondition.java
// Using finalize() to detect an object that
// hasn't been properly cleaned up.

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");
    // Normally, you'll also do this:
    // super.finalize(); // Call the base-class version
  }
}

public class TerminationCondition {
  public static void main(String[] args) {
    Book novel = new Book(true);
    // Proper cleanup:
    novel.checkIn();
    // Drop the reference, forget to clean up:
    new Book(true);
    // Force garbage collection & finalization:
    System.gc();
  }
} /* Output:
Error: checked out
*///:~
        垃圾回收器在内存快要耗尽时开始工作,回收不再使用的对象。很多虚拟机中堆的实现如下:它更像一个传送带,每分配一个新对象,它就往前移动一格。为了做到这一点,垃圾回收期需要整理内存,其有两种方法:“停止——复制”和“标记——清扫”。对于比较稳定的程序(没有新垃圾产生),其会进入“标记——清扫”模式。

       另外,java虚拟机为了提高速度,使用了“即时(Juse-in-Time,JIT) ”编译技术,先将类编译为.class文件,然后再将该类的字节码装入内存。此时有两种方法:一种是让即时编译器编译所有代码;另一种是使用惰性评估,意思是即时编译器只在必要的时候才编译代码。

5.6 成员初始化

      总结一下对象的创建过程,假设有名为dog的类:

      1)即使没有显示的使用static关键字,构造器实际上也是静态方法。因此,首次创建类型为dog的对象时(构造器可以看成静态方法),或者dog类的静态方法/静态域首次被访问时,java解释器必须查找类路径,以定位dog.class文件。

      2)然后载入dog.class(后面会学到,这将创建一个class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在class对象首次加载的时候进行一次。

      3)的那个用new dog()创建对象时,首先将在堆上为dog对象分配足够的存储空间。

      4)这块存储空间会被清零,这就自动地将dog对象中的所有基本类型数据都设置成默认值(对数字来说就是0,对布尔型和字符型也相同),而引用则被设置成null。

      5)执行所有出现于字段定义处的初始化动作。

      6)执行构造器。正如将在第7章所看到的,这可能会涉及到很多动作,尤其是涉及继承的时候。

      显示静态初始化:

//: initialization/Spoon.java
public class Spoon {
  static int i;
  static {
    i = 47;
  }
} ///:~
      static后面的代码跟静态初始化动作一样,这段代码仅执行一次:当首次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员时。

       非静态实例初始化:

//: initialization/Mugs.java
// Java "Instance Initialization."
import static net.mindview.util.Print.*;

class Mug {
  Mug(int marker) {
    print("Mug(" + marker + ")");
  }
  void f(int marker) {
    print("f(" + marker + ")");
  }
}

public class Mugs {
  Mug mug1;
  Mug mug2;
  {
    mug1 = new Mug(1);
    mug2 = new Mug(2);
    print("mug1 & mug2 initialized");
  }
  Mugs() {
    print("Mugs()");
  }
  Mugs(int i) {
    print("Mugs(int)");
  }
  public static void main(String[] args) {
    print("Inside main()");
    new Mugs();
    print("new Mugs() completed");
    new Mugs(1);
    print("new Mugs(1) completed");
  }
} /* Output:
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
*///:~
     这种语法对于支持“匿名内部类”的初始化是必须的,但是它使得你可以保证无论调用了哪个显示构造器,某些操作都会发生。从输出可以看出,实例初始化子句是在两个构造器之前执行的。

5.8 数组初始化

      int[] a1={1,2,3,4,5,6,}//最后一个逗号可以不要

      int a2[];

      a2=a1;//此时a2是a1的引用。

      另外,数组可以在程序中间用new来初始化。比如:a1=new int[rand.nextInt(20)]

      可变参数列表有两种形式:jiuba




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值