第五章 初始化与清理

初始化和清理 (cleanup) 是涉及安全的两个问题,由此引入了 构造器 (constructor) 这个概念。


1. 关于初始化

  • 在 java 中,创建对象,如果具有构造器,那么 java 会在操作对象之前自动调用相应的构造器,从而保证初始化的进行。
  • 构造器采用了与类相同的名称,所以“,每个方法首字母小写”的编码风格并不适合构造器。
  • 不接受任何参数的构造器被称为 默认构造器, java 文档中称为 无参构造器,接收参数的被称为带参构造器。
  • 在 java 中 ,初始化 和 创建 是绑定在一起的,两者不能分离。构造器是一种特殊类型的方法,因为他没有返回值。

2. 关于方法重载

  • 为了让方法名相而形式参数不同的构造器同时存在,必须用到方法重载。
  • 要区分几个相同名字的方法,每个重载的方法都必须有一个独一无二的参数类型列表。(参数的顺序不同也可以区分,但是不利于维护,一般不建议这样用)
  • 基本类型能从一个 “ 较小” 的 类型自动提升到一个 “较大” 的类型,此过程一旦牵涉到重载,可能会造成一些混淆。如果传入的数据类型(实际参数类型)小于方法中声明的形式参数类型,实际数据类型就会被提升。
  • 如果传入的实际参数较大,就得通过类型转换来执行窄化转换,如果不这样做,编译器就会报错。
  • 根据返回值来区分重载方法是行不通的。

3. 关于默认构造器

  • 如果你写的类中没有构造器,那么编译器会自动帮你创建一个默认的构造器。但是,如果你自己已经定义了一个构造器(无论这个构造器是否有参数),编译器都不会再帮你自动创建一个默认的构造器。

4. 关于this关键字

  • this 关键字只能在方法内部分使用,表示调用方法的那个对象的引用。
  • 如果在方法内部调用同一个类的另一个方法,就不必使用 this ,直接调用即可,当前方法中的 this 会自动应用于同一个类中的其他方法。

    public class Apricot(){
    void pick(){
       /*  */
    }
    void pit(){
         pick();     // 相当于  this.pick();   但是没必要这样写
         /*   */
    }
    }

public class For4Test9 {
  int a = 0;
  For4Test9 increat(){
      a++ ;
      return this ;
  }
  void print(){
      System.out.println("i = " + a);
  }
  public static  void main(String[] args){
      For4Test9 f = new For4Test9() ;
      f.increat().increat().increat().increat().increat().print();
  }
  /*
  * increat() 通过this关键字返回了对当前对象的引用,所以很容易在一条语句里对同一个对象执行多次操作。
  * */

}
this 关键字对于将当前对象传递给其他对象
class Person{
  public void eat(Apple apple){
    Apple peeled = apple.getPeeled() ;
    System.out.println("xxxxxxxxxxxxxxxxxxx") ;
  }
}
class Peeler{
  static Apple peel(Apple apple){
    return apple ;
  }
}
class Apple{
  Apple getPeeled(){
    return Peeler.peel(this) ;
  }
}

public class For4Test9 {
  public static  void main(String[] args){
    new Person().eat(new Apple());
  }
}
  • 在构造器中调用构造器。 通常写 this 的时候,都是指 “这个对象” 或者 “当前对象” ,而且他本身表示对当前对象的引用。
  • 在构造器中,如果为 “this” 添加了参数列表,那么就有了不同的含义,这将产生对符合此参数列表的某个构造器的明确调用,参数名称和数据成员相同时,会产生歧义, this.s 代表数据成员,即可解决这个歧义。
public class FiveTest8 {
    int petalCount = 0 ;
    String s = "initial value" ;
    FiveTest8(int petal){
        petalCount = petal ;
        System.out.println("Constructor w int arg only ,petalCount = " + petalCount) ;
    }

    FiveTest8(String ss){
        System.out.println("Constructor w String arg only ,s = " +ss);
        s = ss ;
    }

    FiveTest8(String s , int petals){
        this(petals) ;
        this.s = s ;
        System.out.println("String & int args");
    }

    FiveTest8(){
        this("hello" , 47) ;
        System.out.println("default constructor (no args)");
    }


    void printPetalCount(){
        System.out.println("petalCount = " + petalCount + "s = " +s);
    }

    public static void  main(String[] args){
        FiveTest8 five = new FiveTest8() ;
        five.printPetalCount() ;
    }

}

5. static的含义

  • static 方法就是没有 this 的的方法,在 static 方法法的内部,不能够调用非静态的方法,但是反过来可以,即在没有创建任何对象的前提下,仅仅通过类本身来调用 static 方法。

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

  • 在执行垃圾清理时,会先调用 finalize() 方法 . 对象可能不被垃圾回收,垃圾回收不等于 “析构”,垃圾回收只与内存有关。当垃圾回收没有发生的时候, finalize() 永远不会被调用。
  • finalize() 用途。 使用垃圾回收器的唯一原因是为了回收程序不再使用的内存,所以对于与垃圾回收有关的任何行为来说(尤其是 finalize() 方法),他们也必须同内存以及回收有关。所以 finalize() 不是进行普通的清理工作的合适场所。通过某种创建对象方式以外的方式为对象分配了存储空间,需要使用 finalize() 。
  • java不允许创建局部对象,必须使用new创建。无论是,“垃圾回收” 还是 “终结” ,都不一定会保证发生。
  • java从堆分配空间的速度可以和其他语言从堆栈上分配空间的速度媲美。

7. 关于成员的初始化

  • 在 java 中,如果没有对成员进行初始化,那么编译器就会报错,强制程序员进行初始化,基本类型除外,基本数据类型成员都会有一个初始值。在类中定义了一个对象的引用的时候,如果没有对她进行初始化,那么就会获得一个特殊的值 null .
  • 可以指定值进行初始化,可以用构造器进行初始化,
  • 在类的内部,变量的定义的先后顺序决定了初始化的顺序,即使变量定义散布在方法定义之间,他们仍会在任何方法(包括构造器)被调用前得到初始化。
  • 无论创建多少个对象,静态数据都只占用一份存储区域,static 不可用于局部变量,只能作用于域。静态数据只有在必要的时候才会进行初始化。
  • 初始化的顺序是,先静态对象 ( 如果他们尚未因为前面的对象创建过程而被初始化 ) ,之后是非静态对象。
  • 即使没有显式的使用 static 关键字,构造器实际上也是静态方法,创建对象的时候,在堆上为这个对象分配足够多的空间,
  • 静态代码块也只执行一次,当首次生成这个类的一个对象的时候,或者首次访问这个类的静态数据成员的时候,会执行。
  • 实例的初始化是在构造器之前执行的。
  • 如果创建了一个非基本类型的数组,就创建了一个引用数组,

8. 枚举类型

enum关键字,枚举类型是定义好的枚举类,有三种方式使用:

  • 直接定义枚举变量,默认是 private 类型
  • 使用带构造器创建
  • 使用内部类创建

由本人从 Thinking in java ( java 编程思想 ) 整理而来

最后修改:2018 年 07 月 15 日
哇卡哇卡