Java编程思想之初始化与清理

时间:2021-05-09 18:19:43

1. 用构造器确保初始化

  • 构造器采用与类名相同的名称,调用构造器是编译器的责任。
  • 构造器有无参构造器(默认构造器)以及有参构造器,构造器无返回值。
  • 当没有定义类的构造器时,创建对象直接调用默认构造方器。
  • 当定义了有参构造器时,如需调用无参构造器,则需申明无参构造器。
  • 在多线程情况下,只能有一个线程调用某一个对象的构造方法,因此构造方法是同步的。

2. 方法重载

  • 区分方法重载是,每个重载方法参数列表是不一样的,甚至参数顺序不一样也足以区分两个方法,但一般情况不这么做。而与返回值无关。
  • 基本类型可以从一个较小的类型自动提升至一个较大的类型。
  • 如果传入一个较大的类型将需要显示的类型强制转换,不然编译器会报错。

4. this关键字

  • this关键字就是当前对象的引用。
  • 在构造器中调用构造器:
    • 调用构造器的这条语句必须在第一句。
    • 尽管可以用this调用一个构造器,但是不能调用两个。
    • 除构造器之外,编译器禁止在任何其他方法中调用构造器。
package initialization;

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

public class Flower {
    int petalCount = 0;
    String s = "initial value";

    Flower(int petals) {
        petalCount = petals;
        print("Constructor w/ int arg only, petalCount= " + petalCount);
    }

    Flower(String ss) {
        print("Constructor w/ String arg only, s = " + ss);
        s = ss;
    }

    Flower(String s, int petals) {
        this(petals);
        // ! this(s); // Can't call two!
        this.s = s; // Another use of "this"
        print("String & int args");
    }
    Flower() {
        this("hi", 47);
        print("default constructor (no args)");
    }
    void printPetalCount() {
        // ! this(11); // Not inside non-constructor!
        print("petalCount = " + petalCount + " s = " + s);
    }

    public static void main(String[] args) {
        Flower x = new Flower();
        x.printPetalCount();
    }
} /* * Output: Constructor w/ int arg only, petalCount= 47 String & int args default * constructor (no args) petalCount = 47 s = hi */// :~

1. static的含义

  • 了解完this关键字之后,就能更全面的理解static(静态)方法的含义。static方法就是没有this指针的方法。
  • 在static方法的内部不能调用非静态方法,反过来可以。
  • 可以在没有创建任何对象的前提下,通过类名.方式调用方法。
  • static可以修饰变量、常量、方法、类名,一经修饰,则说明该内容为类所共有,所有类的对象共享。

5. 清理:终结处理和垃圾回收

1. finalize的用途以及介绍

  • 垃圾回收器只知道回收由new分配的内存。一旦垃圾回器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
  • 所以要是打算使用finalize(),就能在垃圾回收时刻做一些重要的清理工作。
  • 或者可以在finalize()方法里进行自救(重新与引用链上的任何一个对象建立连接即可),譬如把自己this引用赋值给某个类变量或对象的成员变量。
  • 但是,这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次。

2. finalize、final、finally的区别

  1. 性质不同

    • finalize()为方法;
    • final为关键字;
    • finally为区块标志,用于try语句中;
  2. 作用

    • finalize():Object中进行了定义,用于在对象“消失”时,由JVM进行调用用于对对象进行垃圾回收。用户自定义时,用于释放对象占用的资源(比如进行I/0操作)。
    • final:修饰的变量,方法,类,代表变量值不可改,方法不可被重写,类不能被继承。final标识的关键字存储在常量池中。
    • finally:finally{}用于标识代码块,与try{}进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行。

6. 成员初始化

  • Java尽力保证所有变量在使用前都能得到恰当的初始化。对于方法的局部变量,Java以编译时错误的形式来贯彻这种保证。
  • 类的数据成员是基本类型都会保证有一个初始值,如int为0,boolean为false等。
  • 如果是一个对象引用时,默认初始化为null。
  • 指定初始化:
public class InitialValues2 {
    boolean bool = true;
    char ch = 'x';
    byte b = 47;
    short s = 0xff;
    int i = 999;
    long lng = 1;
    float f = 3.14f;
    double d = 3.14159;
}

7. 构造器初始化

可以用构造器来进行初始化。在运行时刻,可以调用方法或执行某些工作来确定初值,为编程带来了更大的灵活性。但注意:无法阻止自动初始化的进行,它将在构造器被调用之前发生。因此,如下代码:

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

那么i首先会被置为0,然后变成7。对于所有基本类型和对象的引用,包括在定义时已经指定初值的变量,这种情况是成立的,而final常量则不是,而是直接指定。

1. 初始化顺序

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

2. 静态数据的初始化

  • 无论创建多少个对象,静态数据只占一份存储区域。
package initialization;//: initialization/StaticInitialization.java
// Specifying initial values in a class definition.

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)

对象创建过程:

类变量/静态代码块->main()->实例变量/构造块->构造方法

  1. 即使没有显示的使用static关键字,构造器实际上是静态方法。因此首次创建类型为Dog的对象时,或者Dog类的静态方法/静态域首次被访问时,java解释器必须查找类路径,以定位Dog.class文件。
  2. 然后载入Dog.class,有关静态初始化的所有动作都会执行。因此,静态初始化旨在Class对象首次加载的时候进行一次。
  3. 当用new Dog()创建对象时,首先在堆上为Dog对象分配足够的存储空间。
  4. 这块存储空间会被清零,这就自动地将Dog对象中所有的基本类型数据都设置了默认值,而引用也被设置成了null。
  5. 执行所有出现于字段定义出的初始化动作。
  6. 执行构造器。