Java编程思想读书笔记(4):初始化与清理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hf19931101/article/details/86655059

四、初始化与清理

  1. 执行构造函数实际上分为三阶段:
  1. 调用父类的构造函数
  2. 用这些字段的初始器和初始化块来初始化它们;
  3. 执行构造函数体
  1. 如果我们为类编写了一个或多个构造器那么jvm就不会生成默认构造器了。

  2. Java中区分重载方法的规则:每个重载的方法都必须有一个独一无二的参数类型列表。(参数顺序的不同也可以,但这样会使代码难以维护);不能使用返回值来区分重载方法。

  3. 涉及基本类型的重载:

    1. 重载时,如果传入的实际参数类型“小于”方法中声明的形式参数类型,实际参数的类型就会被自动“提升”至刚好比实际参数类型大的类型。Char型略有不同,如果找不到恰好接受char参数的方法,就会把char直接“提升”至int型。
    2. 如果方法接受“较小”的参数类型,而传入的实际参数类型“较大”,就得做必要的显式类型转换,否则编译器会报错。
  4. this关键字:只能在方法内部使用,表示对“调用方法的那个对象”的引用。一般在必要时,才使用this,比如使用this明确引用类的数据成员。

如果想在一个构造器中调用另一个构造器,使用this关键字。在构造器中,如果为this添加了参数列表,那么就有了不同的含义:这将产生对符合此参数列表的某个构造器的明确调用。

注:必须将构造器调用放在最起始处,否则编译器会报错。使用super()调用基类构造器时必须放在最起始处。且一次只能调用一个构造器。

  1. static的含义:静态方法就是没有this的方法。
    1. “静态方法”内部不能调用“非静态方法”,反过来是可以的。
    2. 在类中置入静态方法,就可以访问其他静态方法和静态字段。

注:传递一个对象到静态方法里,然后就可以访问非静态方法了,但是通常为了达到这种效果。只需写一个非静态方法

  1. finalize():用于那些不是由java创建对象方式(不是new方式分配的内存)为对象分配的存储空间的释放。

    1. 对象可能不被垃圾回收。
    2. 垃圾回收并不等于“析构”。
    3. 垃圾回收只与内存有关。
  2. 在程序中可以通过函数System.gc()强制终止程序,执行finalize()方法。(并不绝对)垃圾回收机制的工作方式有:“停止-复制”和“标记-清扫”。

  3. 初始化的顺序是先“静态”,后“非静态”。
    总结一下对象的创建过程,假设有个名为Dog的类:

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

  5. 数组初始化,可以通过以下几种方式实现:

    1. 聚合初始化:int[] a1 = {1,2,3,4,5} ;
    2. 数组复制:int[] a2; a2=a1; //实际上是将a1的引用复制给a2
    3. 通过new方式,可能的话应该尽量这么做:
      int[] a = new int[rand.nextInt(20)];
    4. 聚合同new方式结合:
      Integer[] b = new Integer[]{ new Integer[1],new Integer[2],new Integer[3] };
    5. 定义后使用for逐个初始化:

注:
(1)所有数组中都包含一个固定成员length,表明数组的长度。
(2)如果数组中存储的是对象,当你试图使用数组中的空引用时,就会在运行时产生“异常”。

  1. J2SE5中的新特性:可变参数列表:即调用方法时,提供的参数是可变个数的。
    例如:
static void printArray(Object... args) {
	for (Object obj : args) {
		System.out.println(obj);
	}
}

调用时,可提供任意个数的参数。如:printArray(1,2); printArray(“one”, “two”, “three”); printArray();
可变参数列表实际上等效于参数数组语法,上面的函数等效于:

static void printArray(Object[]  args) {
	for (Object obj : args) {
	    System.out.println(obj);
	}
}

有了可变参数,就再也不用显示地编写数组语法了。当你指定参数时,编译器实际上会为你去填充数组。
但可变参数列表使得重载变得复杂。例如一下两个方法:

static void f(Character... args) {
	//….
}
static void f(Interger... args) {
	//…
}

调用方法:f(‘a’,‘b’,‘c’);f(1,2); 没有问题,因为编译器会使用自动包装机制来匹配重载的方法,然后调用最明确匹配的方法。但调用方法f()时,编译器无法知道应该调用那个方法,会产出编译错误。可以通过在方法中加入一个非可变参数来解决该问题。

注:应该总是只在重载方法的一个版本上使用可变参数列表,或者压根就不使用它。

  1. 枚举类型:enum。例如:
public enum Spiciness {
    NOT, MILD, MEDIUM, HOT, FLAMING
}

Spiciness howHot = Spiciness.MEDIUM;

创建enum时,编译器会自动添加一些有用的特性,例如

  • toString()方法,用来显示某个enum实例的名字
  • ordinal()方法,用来表示某个特定enum变量的声明顺序;
  • static values()方法,用来按照enum常量的声明顺序产生常量值数组。

enum有一个特别适用的特性是,它可以和switch语句结合使用:

Spiciness degree = Spiciness.MEDIUM;

switch(degree) {
    case NOT: 
    case MILD:
    case MEDIUM:
    case HOT:
    case FLAMING:
    default:
}

猜你喜欢

转载自blog.csdn.net/hf19931101/article/details/86655059
今日推荐