第五章 初始化与清理

5.1 用构造器确保初始化

  1. 构造器的作用
  • 确保每个对象在创建之前得到初始化;
  1. 构造器的调用时机
  • 在创建对象之前自动调用,从而保证了初始化的进行;
  1. 默认构造器
  • 定义:不接受任何参数的构造器叫默认构造器,也叫作无参构造器
  • Tree t = new Tree(12);
  • 如果Tree(int)是Tree类中唯一的构造器,那么不允许以其他的任何方式创建Tree对象;
  • 如果Tree类中没有构造器,那么只能使用new Tree();的方式创建对象,这个时候系统会自动的构建无参构造器,因此即使类中没有构造器,同样能够创建对象,但只能用这一种方式;
  1. 类名的命名规则
  • 类的名字必须和文件名一样,首字母必须大写;

5.2 方法重载

方法重载的定义:

  • 方法名相同而形式参数不同的方法;
  • 方法重载可以应用于类的构造器方法,也可以用于普通方法;

5.2.1 区分重载方法

  • 每个重载方法都必须有一个独一无二的参数类型列表;
  • 参数的顺序不同也可以作为区分重载方法的依据,但是从代码可维护性角度考虑,不推荐这样做;

5.2.2 涉及基本类型的重载

  • 首先按照类型进行排序 char>byte>short>int>long>float>double;
  • 如果传入的类型小于声明的类型,那么就会被提升,对应参数类型的方法将会被调用
public class Test {
    void f(short x){ System.out.println("f(short)"); }
    void f(int x){ System.out.println("f(int)"); }
    void f(long x){ System.out.println("f(long)"); }
    void f(float x){ System.out.println("f(float)"); }
    void f(double x){ System.out.println("f(double)"); }

    void test(){
        char x='x';
        //看到传入的char类型的
        f(x);
    }
    public static void main(String[] args) {
        Test test=new Test();
        //由输出结果可知,char被提升为int类型
        //被提升后,第二个接收参数类型为int的方法被调用
        test.test();
    }
}
  • 如果传入的类型小于声明的类型,提升的规则为:

int => long
char => int
byte => short
short => int
long => float
float => double

  • 如果传入的类型大于声明的类型,必须手动进行窄化处理,不然编译无法通过;

5.2.3 以返回值区分重载方法

  • 是不能用返回值区分方法重载的,编译器就无法通过;

5.3 默认构造器

  • 定义:没有定义参数的构造器,又名无参构造器
  • 如果类中没有构造器,编译器会自动创建一个构造器;
  • 如果已经定义了一个构造器(无论是否有参数),编译器都不会再自动创建默认构造器;

5.4 this关键字

  • 在方法的内部获得对当前对象的引用;
  • 只能在方法内部使用;
  • 在方法内部调用同一个类的另一个方法,就不必使用this,因为方法中的this引用会自动应用于同一类的其它方法;

5.4.1 在构造器中调用构造器

  • this的一般用法是指“这个对象”或者“当前对象”,本身表示对当前对象的引用;
  • 如果为this添加了参数列表,表示明确调用了符合参数列表类型格式的构造器
  • 注意事项: 不能使用超过1个的this调用构造器模式,且必须将构造器调用置于最起始处;

5.4.2 static的含义

  • 在static方法的内部不能调用 非静态方法和非静态数据成员,只能访问其他static方法和static域;
  • 在非静态方法的内部可以调用静态方法;
  • 可以使用类本身直接调用静态方法;

5.6 成员初始化

  • 方法的局部变量 必须要先初始化,否则编译器会报错;
  • 类的数据成员 是基本类型时,如果没有显示的初始化,都会自动的赋予默认值,具体如下:
    boolean flag = false;
    char c = ' ';
    byte b = 0;
    short s = 0;
    int i = 0;
    long l = 0;
    float f = 0;
    double d = 0.0;
    Test test = null;   //引用类型

5.6.1 指定初始化

  • 直接在定义类成员变量的地方为其赋值;
  • 没有初始化的非基本类型对象不能使用,会报错空指针异常;

5.7 构造器初始化 ★★★★★

  • 构造器初始化无法阻止 自动初始化 的进行,它将在构造器被调用之前发生;
public class Counter {
    //step1:先自动初始化为0
    int i;

    Counter() {
        //step2:再执行构造器初始化
        i = 7;
    }
}

5.7.1 初始化顺序

class Window {
    Window(int marker) {
        System.out.println("Window(" + marker + ")");
    }
}

class House {
    Window window1 = new Window(1); //step2:执行构造函数之前先自动初始化

    House() {
        System.out.println("House()");      //step5
        window3 = new Window(33);   //step6:window3变量初始化了两次
    }

    Window window2 = new Window(2); //step3:不管类定义变量散步在什么位置

    void f() {
        System.out.println("f()");  //step8
    }

    Window window3 = new Window(3); //step4
}

public class OrderOfInitialization {
    public static void main(String[] args) {
        House h = new House();  //step1:创建house对象
        h.f();  //step7
        House h1=new House();   //step8:静态类变量只会初始化一次
        h1.f();
    }
}

/**
 * 输出:
 * Window(1)
 * Window(2)
 * Window(3)
 * House()
 * Window(33)
 * f()
 * Window(1)
 * Window(2)
 * Window(3)
 * House()
 * Window(33)
 * f()
 */

5.7.2 静态数据的初始化

  • 无论创建多少对象,静态数据都只占用一份存储区域(即只会 自动初始化一次);
  • static关键字不能应用于局部变量,即不能在方法作用域中使用static声明变量;
  • 在创建类对象之前或者直接引用类静态变量之前都会执行静态变量初始化;
  • 构造函数也是静态方法,因此在调用构造函数之前也会执行静态初始化;

无继承的初始化顺序总结:

  1. 在调用类的静态变量、静态方法(包括构造函数)之前都先执行静态初始化,且只执行一次;
  2. 每次创建对象调用构造方法执行之前,都会先执行自动初始化;

5.7.3 显示的静态初始化

  • 把多个静态初始化动作用 static{} 包装形成静态代码块

无继承的初始化顺序总结:

  1. 在调用类的静态变量、静态方法(包括构造函数)之前都先执行静态初始化,且只执行一次;
  2. 如果有静态代码块,那么再执行静态代码块的内容,且只执行一次;
  3. 在每次创建对象调用构造方法执行之前,都会先执行自动初始化;

5.7.4 非静态实例初始化

  • 把多个非静态基础变量、引用变量的初始化动作用 {} 包装形成实例代码块

无继承的初始化顺序总结:

  1. 在调用类的静态变量、静态方法(包括构造函数)之前都先执行静态初始化,且只执行一次
  2. 如果有静态代码块,那么再执行静态代码块的内容,且只执行一次
  3. 每次创建对象调用构造方法执行之前,都会先执行自动初始化;
  4. 如果有实例代码块,那么再执行实例代码块的内容;

5.8 数组初始化

  • 创建数组的两种形式:
int[] arr = {1, 2, 3};
int[] arr = new int[]{1,2,3};
  • 数组自动初始化,引用类型为null,数字和字符是0,布尔型是false

5.8.1 可变参数列表

  • 当方法的参数具有可选的尾随参数时,就可以把这些参数填充组成一个数组;
  • 编译器会使用自动包装机制来匹配重载的方法;

5.9 枚举类型

  • 枚举类型的实例是常量,因此命名惯例都用大写字母表示;
  • 使用enum,需要创建一个该类型的引用,然后将enum实例赋值给这个引用;
	enum Spiciness {
	    NOT, MILD, MEDIUM, HOT, FLAMING
	}
    public static void main(String[] args) {
        //values:用来按照enum常量的声明顺序,产生由这些常量值构成的数组
        //遍历enum常量值构成的数组,然后使得应用指向这个实例常量
        for (Spiciness s : Spiciness.values()) {
            //s.toString():直接答应实例常量的名字
            //s.ordinal():表示某个特定enum常量的声明顺序
            System.out.println(s + ", ordinal " + s.ordinal());
        }
    }
	/**
	 * NOT, ordinal 0
	 * MILD, ordinal 1
	 * MEDIUM, ordinal 2
	 * HOT, ordinal 3
	 * FLAMING, ordinal 4
	 */
  • enum还可以在switch语句内使用

参考书籍 《java编程思想》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值