《JAVA编程思想(第四版)》第五章(初始化与清理)小结
1.1构造器的作用:确保初始化.
规定名称与类名相同.所以"每个方法首字母小写"的编码风格并不适用于构造器.
public class dog {
String name;
public dog() {
System.out.println("生成一只狗!");
name = "dog";
System.out.println("给狗命名为" + name);
}
public static void main(String[] args) {
//生成10只狗
for (int i = 0; i < 10; i++) {
new dog();
}
}
}
/**
生成一只狗!
给狗命名为dog
...8次...
生成一只狗!
给狗命名为dog
*/
很简单的可以看出,每次new一个对象的时候,就是通过构造器生成一个对象,我们可以在构造器中初始化属性.
构造器可以有多个.比如我们不满意上面的狗名全是dog,可以增加一个参数,改变狗名字.这说明:构造器支持重载.
public class dog {
String name;
public dog(int n) {
System.out.println("生成一只狗!");
name = "dog" + n;
System.out.println("给狗命名为" + name);
}
public static void main(String[] args) {
//生成10只狗
for (int i = 0; i < 10; i++) {
new dog(i);
}
}
}
/**
生成一只狗!
给狗命名为dog0
...1--8....
生成一只狗!
给狗命名为dog9
*/
1.1.1重载方法的小tips
- 同一个类中的方法的名字相同时,参数不同(包含顺序,个数,类型.etc)时,即为重载方法.
- 重载时,应该注意类型提升问题,
- 当使用byte,short,等参数依次遍历重载方法,当遇到可以被兼容的类型(例如:int)时,立刻调用方法,无视剩余方法,
- char类型则是遍历寻找参数为:char的方法,如果没有找到,也将提升为int类型.
- 返回值并不能区分重载方法.他们可能相同,也可能不同.
1.1.2默认构造器
在程序员没有写构造器的时候,编译器会添加一个默认的构造器,方法参数为空,方法体为空.
当程序员为某类写一个及以上的构造器时,编译器将不再为该类添加构造器.
1.2this关键字
假如你期望在方法内部获取到当前对象,那么this关键字就是java提供的手段.
public class TestThis {
String name = "test";
public void a(){
}
void b() {
this.a();//调用当前对象的a()方法
//但是往往我们更喜欢直接使用,二者是等价的,并且后者确实更实用.
a();
//因为编译器会帮我们改变a()为:this.a()
}
void c(String name){
//此时参数名与类的字段名重复,可以使用this关键字区分
this.name = name;
//this表示该对象,所以this.name表示:该对象的name
}
}
1.2.1构造器中调用构造器.
public class ReConstructor {
String name;
int flag;
public ReConstructor() {
this("defaltName", 999);
// 注意:必须放在第一行.
}
public ReConstructor(String name, int flag) {
this.name = name;
this.flag = flag;
}
}
千万注意:一定要把this调用构造器放在第一行,否则将会报错.
2.清理:终结处理和垃圾回收
2.1 GC回收的tips
Java中的对象并非总是被垃圾回收,或者或:
- 对象可能不被垃圾回收.
- 垃圾回收并不等于C++语言中的"析构".
- 垃圾回收只与内存有关.
- 完全由JVM判断,程序员只能提出建议.
- 如果JVM并未面临内存耗尽的情形,他是不会浪费时间去执行垃圾回收以回复内存的.
举个小例子:char[ ] 往往比String 更安全,因为String为不可变,当我们以为它消失的时候,GC并未启动,此时String的数据仍在内存中.而char数组可以被覆盖.(GC只在内存快要耗尽的情况下启动,因为太过频繁的回收将拖累整个效能).
2.2垃圾回收器如何工作.
篇幅过多,只简单说
- JVM在内存耗尽时,启动GC,回收垃圾.
- 而由于GC的存在.提高了对象的创建速度
- 平时GC使用"标记--清扫"模式,当检测到堆空间出现很多碎片,就会切换到"停止--复制"模式
3成员初始化
Java尽力保证:所有变量在使用前都能得到恰当的初始化.对于方法的局部变量,Java以编译时错误的形式来贯彻这种保证.
public class InitData {
public static void main(String[] args) {
int i;
i++; //异常:The local variable i may not have been initialized
//编译时异常,即变量未初始化.
System.out.println(i); //输出 0
//这样是对的,因为编译器赋默认值i = 0,但是编译器无法保证是否是由于程序员的疏忽,所以上一句为错.
}
}
初始化的顺序也应该被注意.不要出现向前引用的情况.
public class InitData {
int j = g(i); //报错,因为此时 i 还未定义
int i =f();
int f() {
return 1;
}
int g(int i) {
return i*i;
}
}
3.1构造器初始化.
public class InitData {
int i = 11;//调用任何构造器之前,i的值已经在这里被初始化了.
public InitData() {
System.out.println(this.i);
i = 7;//初始化i的值.
//两次初始化拥有先后顺序,这可以很好地保证变量被初始化了.
}
public static void main(String[] args) {
new InitData(); //输出11
}
}
现在最好可以记住两次初始化的顺序,后来的继承初始化的顺序容易被混淆.