首页 > 代码库 > 《java编程思想》读书笔记(二)第五章(2)

《java编程思想》读书笔记(二)第五章(2)

成员初始化

  Java尽力保证:所有变量在使用前都能得到恰当的初始化。

  对于方法的局部变量,Java会以编译时报错的形式贯彻这种保证,比如:

1 void f()
2 {
3       int i;  //这里编译时就会报错,未初始化    
4 }

  但是如果是类的数据成员,情况会有所不同。类的每个基本类型数据成员会保证一个默认初始值,通常为0,布尔型就是false,引用类型会为null。

  指定初始化

    (1 直接在类里定义时写变量等于多少(这样在C++中是不允许的)如, 

public class initialV
{
    int a=1;
    char c = ‘c‘;
    //...等等      
}

构造器初始化

  可以用构造器进行初始化。但应注意:无法阻止自动初始化的进行,它将在构造器之前发生。

public class Counter
{
    int i;
    Counter()
    {
         i=7;
    }
}    

这里,i首先会被置0,然后变成7.对于所以基本类型和对象引用,包括在定义时已经指定初值的变量。这种情况都是成立的。

 

初始化顺序

  在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。如下例子

class Window {
  Window(int marker) { print("Window(" + marker + ")"); }
}

class House {
  Window w1 = new Window(1); // Before constructor
  House() {
    // Show that we‘re in the constructor:
    print("House()");
    w3 = new Window(33); // Reinitialize w3
  }
  Window w2 = new Window(2); // After constructor
  void f() { print("f()"); }
  Window w3 = new Window(3); // At end
}

public class OrderOfInitialization {
  public static void main(String[] args) {
    House h = new House();
    h.f(); // Shows that construction is done
  }
} /* 输出:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
*///:~

 

静态数据的初始化

   类的静态成员 属于 类 而不是类 的实例。所以 ,无论你创建多少个对象,静态成员指占用一份存储区域。static关键字不能应用于局部变量,因此只能作用于域。初始化方式和非静态一样。

   给看一个挺长的例子,看不懂直接调后面的解析。

import static net.mindview.util.Print.*;

class Bowl {
  Bowl(int marker) {
    print("Bowl(" + marker + ")");
  }
  void f1(int marker) {
    print("f1(" + marker + ")");
  }
}

class Table {
  static Bowl bowl1 = new Bowl(1);
  Table() {
    print("Table()");
    bowl2.f1(1);
  }
  void f2(int marker) {
    print("f2(" + marker + ")");
  }
  static Bowl bowl2 = new Bowl(2);
}

class Cupboard {
  Bowl bowl3 = new Bowl(3);
  static Bowl bowl4 = new Bowl(4);
  Cupboard() {
    print("Cupboard()");
    bowl4.f1(2);
  }
  void f3(int marker) {
    print("f3(" + marker + ")");
  }
  static Bowl bowl5 = new Bowl(5);
}

public class StaticInitialization {
  public static void main(String[] args) {
    print("Creating new Cupboard() in main");
    new Cupboard();
    print("Creating new Cupboard() in main");
    new Cupboard();
    table.f2(1);
    cupboard.f3(1);
  }
  static Table table = new Table();
  static Cupboard cupboard = new Cupboard();
} /* 输出:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*///:~

  解析下这个Demo:要执行main()(静态方法) ,必须加载StaticInitialization 类,然后其静态域table和cupboard被初始化,这将导致他们对应的类页被加载,并且由于他们也都包含静态的Bowl对象,因此Bow随后也被加载了。(恍然大悟)

  理论得出:静态初始化只有在必要时刻才会进行。如果不创建Table对象,也不引用Table.b1或Table.b2,name静态的Bowl b1和b2永远都不会被创建。只有在第一个Table对象被创建(或其第一次被访问了静态数据)的时候,它们才会被初始化。此后,静态对象不会再次被初始化

 

显式的静态初始化

  Java允许将多个静态初始化动作组织成一个特殊的“静态字句”(也称 “静态块”),如下。

public class Spoon {
  static int i;
  static {
    i = 47;
  }
} ///:~

  尽管上面的代码看起来像个方法,但它实际只是一段跟在static关键字后面的代码。与其他静态初始化动作一样,这段代码只执行一次:同样的时间,当第一次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员时(即便从未生成过那个类)

非静态实例初始化

  用来初始化每一个对象的非静态变量。如下

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");
  }
} /* 输出:
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
*///:~

这是无论调用了哪个显式构造器,某些操作都会发生。从输出中 可以看到实例化字句 是在构造器之前执行的。

《java编程思想》读书笔记(二)第五章(2)