第六章

构造器初始化

初始化的顺序

在类中变量定义的顺序决定了它们初始化的顺序。即使变量定义散布在方法定义之间,它们仍会在任何方法(包括构造器)被调用之前得到初始化

  1. // housekeeping/OrderOfInitialization.java
  2. // Demonstrates initialization order
  3. // When the constructor is called to create a
  4. // Window object, you'll see a message:
  5. class Window {
  6. Window(int marker) {
  7. System.out.println("Window(" + marker + ")");
  8. }
  9. }
  10. class House {
  11. Window w1 = new Window(1); // Before constructor
  12. House() {
  13. // Show that we're in the constructor:
  14. System.out.println("House()");
  15. w3 = new Window(33); // Reinitialize w3
  16. }
  17. Window w2 = new Window(2); // After constructor
  18. void f() {
  19. System.out.println("f()");
  20. }
  21. Window w3 = new Window(3); // At end
  22. }
  23. public class OrderOfInitialization {
  24. public static void main(String[] args) {
  25. House h = new House();
  26. h.f(); // Shows that construction is done
  27. }
  28. }

引用 w3 被初始化了两次:一次在调用构造器前,一次在构造器调用期间(第一次引用的对象将被丢弃,并作为垃圾回收)。这乍一看可能觉得效率不高,但保证了正确的初始化。

静态数据的初始化

无论创建多少个对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量,所以只能修饰属性(字段 域)。

class Bowl {
    Bowl(int marker) {
        System.out.println("Bowl(" + 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("main creating new Cupboard()");
        new Cupboard();
        System.out.println("main creating new Cupboard()");
        new Cupboard();
        table.f2(1);
        cupboard.f3(1);
    }
    static Table table = new Table();
    static Cupboard cupboard = new Cupboard();
}

初始化的顺序先是静态对象(如果他们没有被初始化),然后是非静态对象。

第十一章节 内部类

当生成一个内部类的对象时,此对象与制造它的外部对象之间就有了一种联系,所以它能访问其外部对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外部类的所有元素的访问权。

内部类自动拥有其外部类所有成员的访问权
当某个外部类的对象创建一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外部类对象的成员。

使用 .this.new

如果需要生成对外部类对象的引用,可以使用外部类的名字紧跟圆点和this。这样产生的引用自动地具有正确的类型。

public class DotThis {
    void f() {
        System.out.println("DotThis.f()");
    }

    public class Inner {
        public DotThis outer() {
            return DotThis.this;
            // A plain "this" would be Inner's "this"
        }
    }

    public Inner inner() {
        return new Inner();
    }

    public static void main(String[] args) {
        DotThis dt = new DotThis();
        DotThis.Inner dti = dt.inner();
        dti.outer().f();
    }
}

有时可能想告知某些对象,去创建其某个内部类的对象。要实现此目的,必须在new表达式中提供其对外部类对象的引用。这是需要.new 语法,如下:


public class DotNew {
    public class Inner {}
    public static void main(String[] args) {
        DotNew dn = new DotNew();
        DotNew.Inner dni = dn.new Inner();
    }
}