ThinkingInJava阅读笔记Chapter5

C++ 引入了构造器的概念,这是一个在创建对象时被自动调用的特殊方法。Java也采用了构造器,并且额外提供了垃圾回收器。

1 用构造器确保初始化

构造器是与对象同名的方法,在使用 new 创建对象时,默认执行对象的无参构造方法执行初始化。

2 方法重载

以构造方法为例,有参构造方法即为重载的构造方法,即同名的方法是方法重载的必要条件。

2.1 区分重载方法

重载方法名称相同,参数列表不同,定义时参数顺序最好有规律性,比如

void fun(int i);
void fun(int i, String s); 
void fun(int i, String s, long l);
复制代码

2.2 涉及基本类型的重载

void fun(short i)
void fun(int i)
复制代码

如果执行 fun(5)实际被调用的方法是void fun(int i)也就是没有指定基本类型的参数类型时,会被默认地提高精度,char 类型如果没有 void fun(char c) 方法,会默认提高精度到int

如果参数精度大于方法参数定义,则需要强转窄化。

2.3 以返回值区分重载方法

不以返回值区分方法的原因是,有时候业务不关注方法的返回值,程序无法识别方法,如

int fun();
String fun();
复制代码

假设上面方法是可用的,在程序中调用fun();程序并不知道要调用哪一个,所以不用返回值区分方法。

3 默认构造器

如果没有显示定义构造器,则默认构造器为无参构造器。

4 this 关键字

this 只能在方法内部使用,表示调用方法的那个对象的引用。

public class PassingThis {
    public static void main(String[] args) {
        new Person().eat(new Apple());
    }
}

class Person{
    public void eat(Apple apple){
        Apple peeled = apple.getPeeled();
        System.out.println("Yummry");
    }
}

class Peeler{
    static Apple peel(Apple apple){
        return apple;
    }
}

class Apple{
    Apple getPeeled(){
        return Peeler.peel(this);
复制代码

this 用于值传递

4.1 在构造器中调用构造器

public class Flower {

    int petalCount = 0;
    String s = "inital value";
    Flower(int petals){
        petalCount = petals;
    }

    Flower(String ss){
        s = ss;
    }

    Flower(int petalCount, String ss){
        this(ss);
    }

    Flower(int petalCount, String ss, long y){
        this.petalCount = petalCount;
    }
复制代码

在构造器中,this()表示调用无参构造器(有参传参数即可)

4.2 static的含义

static 修饰的方法就是没有this 的方法,可以看作是全局方法。

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

垃圾回收器只知道释放那些经由new分配的内存,所以它不知道该如何释放该对象的这块特殊内存。一旦垃圾回收器准备好释放对象占用的存储内空间,将首先调用其finalize方法 ,并且在下一次垃圾回收动作发生时才会真正回收对象占用的内存。

对象可能不被垃圾回收

垃圾回收并不等于析构

5.1 finalize()的用途何在

看不太明白,大致和内存有关,不可过多的使用finalize()

5.2 你必须实施清理

c++中通过析构函数实现对象内存释放,java中由垃圾回收器自动调用,但是也有可能回收不了对象,迷糊。

5.3 终结条件

可以这样理解,垃圾回收时,会调用对象的finalize()方法,可以把一些对该对象的检测逻辑放到finalize()里。

public class TerminationCondition {

    public static void main(String[] args) {
        Book novel = new Book(true);
        novel.checkIn();
        new Book(true);
        System.gc();
    }

}

class Book{
    boolean checkOut = false;

    public Book(boolean checkOut){
        this.checkOut = checkOut;
    }

    void checkIn(){
        checkOut = false;
    }

    protected void finalize(){
        if(checkOut){
            System.out.println("Error : checked out");
        }
复制代码

5.5 垃圾回收器如何工作

1、引用计数法

2、标记-清除法

3、复制算法

等等

developer.ibm.com/zh/articles…

6 成员初始化

类的数据类型是基本类型时会被初始化成对应的类型的初始值。引用类型会声明成null。

6.1 指定初始化

即初始化赋值。

7 构造器初始化

类的成员变量在构造器调用之前就会被初始化。

class Counter{
    int i;
    public Counter(){
        i = 5;
    }
}
复制代码

i在调用构造方法之前就被初始化成0,调用构造方法后被赋值为5

7.1 初始化顺序

即时变量定义散布于方法定义之间,它们仍旧会在任何方法被调用前被初始化。

7.2 静态数据的初始化

静态初始化只有在必要时刻才会进行。

假设有一个Dog类。

1、当首次使用构造方法创建对象时,或许Dog类地静态方法静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class

2、载入Dog.class,有关静态初始化的所有动作都会执行,因此,所有静态初始化旨在Class对象中首次加载的时候进行1次。

3、当用new Dog()创建对象时,首先在堆上为对象分配足够的存储空间。

4、这块存储空间会被清0,所有地成员变量被初始化成0 或null

5、执行所有成员变量初始化动作。

6、执行构造器。

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();
}

class Bowl{
    Bowl(int marker){
        print("Bowl(" + marker + ")");
    }
    void f1(int marker){
        print("f1("+marker+")");
    }
}

class Table{

    static Bowl bowl = new Bowl(1);
    Table(){
        print("Table()");
        bowl2.f1(2);
    }

    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(
复制代码

7.3 显示的静态初始化

静态初始化动作只进行一次。

7.4 非静态示例初始化

{}的语句会在对象初始化之前执行。

8 数组初始化

所有数组都有一个固定成员,可以通过它获取数组内包含了多少个元素,这个成员时length。

数组初始化方式:

Type[] list = new Type[5];

8.1 可变参数列表

可变参数列表本质上就是Object 数组。

9 枚举类型

枚举类型为常量,定义时应该用大写,enum是为了编译器有更好的优化,实际上还是java类,有默认的toString()方法,输出变量名,ordinal()方法,用于枚举定位。

10 总结

初始化和资源回收是面向对象的语言很重要的特性,还需要深入研究,垃圾回收机制虽然占用一部分资源,但慢慢地java的性能提升后也可以慢慢接受。