第五章 初始化与清理
初始化和清理 (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 编程思想 ) 整理而来