第五章 初始化与清理(上)
我已经看过第二、三、四章的内容,发现讲解的都是一些很基本的东西,所以这里就不做详细总结了,我还得继续看后面更重要的内容,并且尝试理解清楚,后面的东西非常重要,但同时又很难,所以总结起来会花费很长时间,现在继续努力。
随着计算机革命的发展,“不安全”的编程方式已逐渐成为编程代价高昂的主因之一。
初始化和清理正式涉及安全的两个问题。
5.1 用构造器确保初始化
在Java中构造器采用与类相同的名称,通过构造器,类的设计者可确保每个对象都会得到初始化,如果类中具有构造器,Java就会在用户有能力操作对象之前自动调用相应的构造器,从而保证了初始化的进行。每个类中都有一个默认的构造器(即里边没有任何参数)。所以只要创建对象,构造器就会执行。如果有多个构造器,那么就会根据你创建的对象来区分了。
构造器是一种特殊类型的方法,因为它没有返回值。这与返回值为空(void)明显不同。对应空返回值,尽管方法本身不会自动返回什么,但仍可选择让它返回别的东西。构造器则不会。当然new表达式确实返回了对创建对象的引用,但本身不返回任何返回值。假如构造器有返回值,并且允许人们自行选择返回类型,那么势必得让编译器知道该如何处理此返回值。
5.2 方法重载
为什么会有方法重载?
第一:方法名其实是我们对某个动作取的名字,一个好的名字可以使系统更易于理解和修改。当对明显相同的概念取不同的名字会让人很难理解,因此有了方法重载就很好的解决了这个问题。在现实生活中会出现一样的人的名字,但是我们可以通过其它的条件来唯一标识。
第二:构造器是强制重载方法名的另一个原因。因为构造器的名字已经由类名所决定,就只能有一个构造器名。那如果想用多种方式创建一个对象应该怎么办?假设要创建一个类,既可以用标准的方式进行初始化,也可以从文件里读取信息来初始化。这就需要两个构造器,一个是默认构造器,另一个里边得有一个字符串作为形式参数的构造器,所以为了让方法名相同而形式参数不同的构造器同时存在,必须用到方法重载。尽管方法重载是构造器必需的,但它亦可应用与其他方法,且用法同样方便。
5.2.1 区分重载方法
要是几个方法都有相同的名字,那么区分规则其实很简单:每个重载的方法都必须有一个独一无二的参数类型列表。
注:参数类型的个数相同但顺序不同也可以区分,不过一般情况不推荐,因为这会使代码难以维护。
5.2.2 涉及基本类型的重载
如果传入的数据类型(实际参数类型)小于方法中声明的形式参数类型,实际数据类型会被提示。char型略有不同,如果无法找到恰好接受int型参数,它会把char直接提升至int型。例如传入的实际参数是int型,然后传入重载方法中为long型的方法,则int型会转换成long型。
如果传入的数据类型(实际参数类型)大于方法中声明的形式参数类型,就得通过类型转换来执行窄化转换。如果不这样,编译器就会报错。
5.2.3 以返回值区分重载方法
首先可以确认这种方法是错误的。例如:
void f(){}
int f(){return 1;}
然后调用的时候是int x=f();,那么这样的确可以区分重载方法,但是有时候我们并不关心方法的返回值,你想要的是其他效果,然后就忽略其返回值。所以,如果像下面这样调用方法:
f();
此时Java如果才能判断该调用哪一个f()呢?别人该如何理解?因此,根据方法的返回值来区分重载方法是行不通的。
5.3 默认构造器
如前所述,默认构造器(又名“无参”构造器)是没有形式参数的——它的作用是创建一个“默认对象”。如果你写的类中没有构造器,则编译器会自动帮你创建一个默认构造器。
注:当你自己定义了一个有形式参数的构造器时,如果你new Bird();这样写,编译器肯定报错:没有找到匹配的构造器。这就好比,要是你没有提供构造器,编译器认为“你需要一个构造器,让我给你制造一个吧”;但假如你已经写了一个构造器,编译器则认为“啊,你已经写了一个构造器,所以你知道你做什么;你是刻意省略了默认构造器”。
5.4 this关键字
this关键字只能在方法内部使用,表示对“调用方法的那个对象”的引用。this的用法和其他对象引用并无不同。但要注意,如果在方法内部调用同一个类的另一个方法,就不必使用this,直接调用即可。因为编译器能自动帮你添加的。
当需要返回对当前对象的引用时,就常常在returne语句中这样写:
public class Leaf {
int i = 0;
Leaf increment() {
i++;
return this;
}
void print() {
System.out.println("i=" + i);
}
public static void main(String[] args) {
Leaf x=new Leaf();
x.increment().increment().increment().print();;
}
}
运行结果: i=3
5.4.1 在构造器中调用构造器
看懂这段代码就明白了:
public class Flower {
int petalCount =0;
String s="initial value";
Flower(int petals){
petalCount = petals;
System.out.println("Constructor w/ int arg only, petalCount="+petalCount);
}
Flower(String ss){
System.out.println("Constructor w/ int arg only, ss="+ss);
s=ss;
}
Flower(String s,int petals){
this(petals);
this.s=s;
System.out.println("String & int args");
}
Flower(){
this("hi",47);
System.out.println("default contructor");
}
void printpetalCount(){
// ! this(11); //not inside non-constructor!
System.out.println("printpetalCount="+petalCount+"s="+s);
}
public static void main(String[] args) {
Flower x=new Flower();
x.printpetalCount();
}
}
运行结果:
Constructor w/ int arg only, petalCount=47
String & int args
default contructor
printpetalCount=47s=hi
5.4.2 static的含义
了解this关键字之后,就能更全面地理解static(静态)方法的含义。static方法就是没有this的方法。在static方法的内部不能调用非静态方法,反过来倒是可以。。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正式static方法的主要用途。它很像全局方法。因为只需要通过类就可以访问到static方法和static域。