《Thanking in Java》5. 初始化与清理

5.1 用构造器确保初始化

构造器有助于减少错误,并使代码更易于阅读。在java中,初始化与创建捆绑在一起,两者不能分离。

构造器没有任何返回值。new表达式确实返回了对新建对象的引用,但构造器本身并没有任何返回值。

5.2 方法重载

每一个重载方法都必须有一个独一无二的参数类型列表。

参数顺序不同也足以区分两个方法,不过一般情况下不这么做,因为这回使得代码难以维护。

如果传入的数据类型(实际参数类型)小于方法中声明的形式参数类型,实际数据类型就会被提升。char型略有不同,如果无法找到恰好接受char参数的方法,就会把char直接提升至int型。如果传入的实际参数较大,就得通过类型转换来执行窄化转换,否则编译器会报错。

根据方法的返回值来区分重载方法是行不通的。

如果已经定义了一个构造器(无论是否有参数),编译器就不会帮你自动创建默认构造器。

5.4 this关键字

this关键字只能在方法内部使用,标识对“调用发放的那个对象”的引用。

this可以返回对当前对象的引用,在return中返回,也可以在方法传递中作为参数调用。

//: initialization/Flower.java
// Calling constructors with "this"
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
*///:~

尽管可以用this调用一个构造器,但却不能调用两个,必须将构造器调用置于最起始处,否则编译器会报错。除构造器之外,编译器禁止在其他任何方法中调用构造器。

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

一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize方法,并在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。

  1. 对象可能不被垃圾回收;
  2. 垃圾回收并不等于“析构”;
  3. 垃圾回收只与内存有关。

使用垃圾回收器的唯一原因是为了回收程序不再使用的内存。

对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。

finalize还有一个有趣的用法,它并不依赖于每次都要对finalize进行调用,这就是对象终结条件的验证。

package chapter5;

/**
 * Created by Blue on 2017/8/29.
 */
class WebBank {
    boolean loggedIn = false;

    WebBank(boolean logStatus) {
        loggedIn = logStatus;
    }

    void logIn() {
        loggedIn = true;
    }

    void logOut() {
        loggedIn = false;
    }

    protected void finalize() {
        if (loggedIn)
            System.out.println("Error: still logged in");
        try {
            super.finalize();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

public class Exercise10 {
    public static void main(String[] args) {
        WebBank bank1 = new WebBank(true);
        WebBank bank2 = new WebBank(true);
        bank1.logOut();
        new WebBank(true);
        System.gc();
    }
}

System.gc()用于强制进行终结动作,既是不这么做,通过重复地执行程序,假设程序将分配大量的存储空间而导致垃圾回收动作的执行。

5.6 成员初始化

方法的局部变量在使用前必须设置初始值。

5.7 构造器初始化

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

无论创建多少个对象,静态数据都只占用一份存储区域,static关键字不能应用于局部变量,因此它只能作用于域。

静态初始化只有在必要时刻才会进行,静态对象不会再次被初始化。

对象的创建过程,假设有个名为Dog的类:

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

代码块优先于构造器初始化。

5.8 数组初始化

有了可变参数,就再也不用显式地编写数组语法了,当你指定参数时,编译器实际上会为你填充数组。0个参数传递给可变参数是可行的。

public class OptionalTrailingArguments {
  static void f(int required, String... trailing) {
    System.out.print("required: " + required + " ");
    for(String s : trailing)
      System.out.print(s + " ");
    System.out.println();
  }
  public static void main(String[] args) {
    f(1, "one");
    f(2, "two", "three");
    f(0);
  }
} /* Output:
required: 1 one
required: 2 two three
required: 0
*///:~

可变参数列表与自动包装机制可以和谐共处。

5.9 枚举类型

enum有一个特别实用的特性,即它可以在switch语句内使用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 初始化与清理是涉及到安全的两个问题。 1.用构造器确保初始化: 当我们通过new关键字来创建对象的时候,就是调用了...
    沈凤德阅读 476评论 2 0
  • 随着计算机革命的发展,“不安全”的编程方式已逐渐成为编程代价高昂的主因之一。 初始化和清理(cleanup)是涉及...
    vernwang阅读 650评论 0 48
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,587评论 18 399
  • 第一章 对象导论 对象具有状态、行为和标识。这意味着每一个对象都可以拥有内部数据和方法,并且每一个对象都可以唯一地...
    niaoge2016阅读 816评论 0 0
  • 宝贝对不起,妈妈试错了 本以为下定决心剪个短发,一剪之前的纠结,让自己轻轻松松继续快乐生活,可是却不是。。。 本以...
    守望者rr阅读 165评论 0 0