On Java8 读书笔记(四)

对象的初始化和清理

"不安全"的编程是造成编程代价昂贵的罪魁祸首之一。有两个安全性问题:初始化和清理。

初始化

构造器

在java中利用构造器初始化,因为构造器能保证进行正确的初始化和清理(没有正确的构造器调用,编译器就不允许创建对象),所以你就有了完全的控制和安全。

构造器分为:

  •        无参构造器(默认)
  •        有参构造器

一旦你显式地定义了构造器(无论有参还是无参),编译器就不会自动为你创建无参构造器。

创建一个对象时,内存被分配,构造器被调用。构造器保证了对象在你使用它之前进行了正确的初始化。

 

有参,无参构造器可以同时存在在一个类里面,两个构造器方法的方法名相同,怎么区分他们呢?

方法重载

方法重载(Overloading)的定义:如果有两个方法的方法名相同,但参数不一致,哪么可以说一个方法是另一个方法的重载。例如:默认构造器(不带参),带参构造器,方法名相同。

区分重载方法:有一条简单的规则:每个被重载的方法必须有独一无二的参数列表。

重载中的基本类型:如果传入的参数类型大于方法期望接收的参数类型,你必须首先做下转换,如果你不做的话,编译器就会报错。

 

this关键字

 通过 this 关键字返回当前对象的引用

 通过this关键字,在构造器中调用构造器

  • 只能通过 this 调用一次构造器
  • this 关键字只能在非静态方法内部使用
  • 必须首先调用构造器,否则编译器会报错
  • 编译器不允许你在一个构造器之外的方法里调用构造器

 

静态方法

static 方法中不会存在 this,静态方法是为类而创建的,不需要任何对象。一个类中的静态方法可以访问其他静态方法和静态属性

Java 尽量保证所有变量在使用前都能得到恰当的初始化。例如:指定初始化,构造器初始化

几种常见初始化(初始化顺序:在类中变量定义的顺序决定了它们初始化的顺序):

  • 静态数据的初始化
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();
}
  • 显式的静态初始化
public class Spoon {
    static int i;

    //"静态子句"(有时叫做静态块)
    static {
        i = 47;
    }
}
  • 非静态实例初始化
class Mug {
    Mug(int marker) {
        System.out.println("Mug(" + marker + ")");
    }
}

public class Mugs {
    Mug mug1;
    Mug mug2;
    { // [1]
        mug1 = new Mug(1);
        mug2 = new Mug(2);
        System.out.println("mug1 & mug2 initialized");
    }

    Mugs() {
        System.out.println("Mugs()");
    }

    Mugs(int i) {
        System.out.println("Mugs(int)");
    }

    public static void main(String[] args) {
        System.out.println("Inside main()");
        new Mugs();
        System.out.println("new Mugs() completed");
        new Mugs(1);
        System.out.println("new Mugs(1) completed");
    }
}
  • 数组初始化

 

  • 动态数组创建

 

枚举类型

由于 switch 是在有限的可能值集合中选择,因此它与 enum 是绝佳的组合。注意,enum 的名称是如何能够倍加清楚地表明程序的目的的。

 

清理

垃圾回收器

  1. 对象可能不被垃圾回收。

  2. 垃圾回收不等同于析构。

  3. 垃圾回收只与内存有关。

C++中你必须实施清理,Java中无论是"垃圾回收"还是"终结",都不保证一定会发生。如果 Java 虚拟机(JVM)并未面临内存耗尽的情形,它可能不会浪费时间执行垃圾回收以恢复内存。

 

finalize的用途

本地方法目前只支持 C 和 C++,但是它们可以调用其他语言写的代码,所以实际上可以调用任何代码。在非 Java 代码中,也许会调用 C 的 malloc() 函数系列来分配存储空间,而且除非调用 free() 函数,不然存储空间永远得不到释放,造成内存泄露。但是,free() 是 C 和 C++ 中的函数,所以你需要在 finalize() 方法里用本地方法调用它

 

终结条件

class Book {
    boolean checkedOut = false;

    Book(boolean checkOut) {
        checkedOut = checkOut;
    }

    void checkIn() {
        checkedOut = false;
    }

    @Override
    protected void finalize() throws Throwable {
        if (checkedOut) {
            System.out.println("Error: checked out");
        }
        // Normally, you'll also do this:
        // super.finalize(); // Call the base-class version
    }
}

public class TerminationCondition {

    public static void main(String[] args) {
        Book novel = new Book(true);
        //正确清理
        novel.checkIn();
        //删除参考,忘记清理
        new Book(true);
        //强制垃圾收集和终结
        //用于强制进行终结动作。
        //但是即使不这么做,只要重复地执行程序(假设程序将分配大量的存储空间而导致垃圾回收动作的执行),
        //最终也能找出错误的 Book 对象。
        System.gc();
        try
        {
            Thread.sleep(2000);
        }
        catch(InterruptedException ex)
        {
            Thread.currentThread().interrupt();
        }

    }

}

输出:

Error: checked out

本例的终结条件是:所有的 Book 对象在被垃圾回收之前必须被登记。但在 main() 方法中,有一本书没有登记。要是没有 finalize() 方法来验证终结条件,将会很难发现这个 bug

 

扩展:垃圾回收器如何工作

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值