zoukankan      html  css  js  c++  java
  • 《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
    *///:~

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

  • 相关阅读:
    Android开发人员不得不收集的代码
    Hadoop HBase概念学习系列之HBase的Shell(步骤非常清晰)(二十四)
    HBase的集群搭建(1、3、5节点都适用)
    Hadoop HBase概念学习系列之HBase里的存储数据流程(二十三)
    Hadoop HBase概念学习系列之HBase里的Client(二十二)
    Hadoop HBase概念学习系列之HBase里的Zookeeper(二十一)
    Hadoop HBase概念学习系列之HFile(二十)
    Hadoop HBase概念学习系列之HBase里的HStore(十九)
    Hadoop Hive概念学习系列之Hive里的2维坐标系统(第一步定位行键 -> 第二步定位字段)(二十三)
    Hadoop HBase概念学习系列之HBase里的4维坐标系统(第一步定位行键 -> 第二步定位列簇 -> 第三步定位列修饰符 -> 第四步定位时间戳)(十八)
  • 原文地址:https://www.cnblogs.com/chz-blogs/p/6254024.html
Copyright © 2011-2022 走看看