第7天的笔记

来源:互联网 发布:mac系统10.13.1 编辑:程序博客网 时间:2024/06/06 00:07

   昨天(星期五)本来挺有空的,但是早上被论坛上的一道题吸引,想了近3个小时;晚上依旧不辍,编ACM的题至凌晨4点……不过这也挺好的,在看书之时可以动动手,看书也会有效率点。贴上今日的笔记:

2011-05-21
1、构造方法(构造器)的访问限制以所在类为基础。即,若构造方法为public而所在类为protected则,包外是不能调用它的。
2、构造方法可以为私有,即外面的别的类而言无法创建其对象。如果想得到这种类的对象,该类必需提供静态方法,就是常说的“静态工厂方法”(这个静态方法具有创建对象的功能,像一个制造对象的工厂一样)。如下代码:

 其中类A的构造方法为私有,外部的类(如这里的Test)是无法创建A的对象的。于是类A提供了静态工厂方法getInstance(),静态方法只属于类,可直接通过类调用之。第10行,就是相当于创建了A的对象a,所以第11行可以通过a来获得成员变量aMamber。
3、构造方法不能有返回(void也算是一种返回),如果有,则不能称之为构造方法,而称与类同名的成员方法。另外,构造方法虽名“方法”,却不可通过对象调用。
4、继承中的构成方法。首先要明确的是,构造方法不能继承。但是:

 运行起来却是打印了“A's constructor”和“A_son's constructor”,即调用子类的构造方法,会把父类也调用了。这是因为构造方法时级联调用的:调用A_son构造方法,级联调用A的,再级联调用A的父类Object,而后执行Object的构造方法,再执行A,再执行A_son。就是说,调用时从底层到最高父类,执行是从最高父类到底层(听着像是中央和地方的关系)。那么编译器如何实现这个机制?其实,如果子类中没有明确的调用父类构造器的代码时,编译器会自动将这个代码添加到子类构造方法的第一行,执行子类构造方法时,即会调用父类的了。这个“自动”当然没有那么人性化,编译器只会自动调用无参构造方法。这个自动添加,也是用于默认的非显式的构造方法(默认非显式构造方法:当程序员不写构造方法时,编译器自动添加的构造方法,一旦写了就不自动添加了)。
5、人为调用父类构造方法。上述的“自动”过程当然可以人为地控制,就是使用上面提到的“调用父类构造器的代码”——super语句。这个语句必须放于子类构造方法的第一行。有了super就可以调用父类的非无参构造方法:我们知道,同一类构造方法之间的区别只是参数列表,所以在super()的括号中,添上适当的参数列表即可识别调用的是哪一个父类的构造方法。具体例子:

 运行结果:
                                                    A's constructor 1
                                                    A_son's constructor 1
                                                    A's constructor 2
                                                    A_son's constructor 2
如果:①将第8行注释掉,结果的第3行打印“A's constructor 1”;②将第8行放于第9行后,编译出错。
6、默认构造方法与级联机制的联合“欺骗”。先看下面一段代码:

 首先说明的是这段代码编译起来会出错。出错并不可怕,可怕的是这个错误教人死活也找不到。鄙人以前犯过这样的错误,并且一直卡在这里……无奈。

其实错误的原因前面的4已经提到了,就是当某个类写了构造方法之后,编译器不在为其添加默认的无参的构造方法。而Test类中,却是调用了A_son(),并且这个构造方法系统会自动为其添加super()语句来调用父类无参构造方法。再观父类,只有一个有参数的构造方法,矛盾之下,错误产生。所以,给每个类都写一个无参构造方法是个好习惯。
7、调用兄弟构造方法(亦称重载的构造方法间的相互调用)。调用兄弟构造方法时用了解决这个情况的:重载构造方法时,这个构造方法可能某些功能与被重载的功能一样,在这个构造方法中调用被重载的。称之为“调用兄弟构造方法”也就是这个原因了。
要在某个类的构造方法调用同在这个类的构造方法,用this()。这个this()性质和super()差不多(只是一个同级之间另一个是上下级之间)

所它们性质差不多,是因为①this()括号里面是放参数列表,以区别调用的是同一类中的哪一个构造方法;②this()必须放于构造器的第一句。对于②,有个很严重的问题,super和this都要要求放在第一句(第一位!?),构造方法却不能提供两个第一句。所以,显式地调用了兄弟的,就不能调用父类的了,反之亦然(忠义两难存!?)。注意前面的“显式”,换言之,可以隐式:子类构造器用来this(),编译器不在自动为其添加super(),但当执行到的时候,还是会添加后调用父类的构造方法,即推迟了super()的调用(java选择了忠!?)
8、避免循环调用。兄弟之间无甚差别,可以相互调用,但不能两个兄弟构造方法互相调用对方,如下面代码:

 会出现“递归构造函数调用”的错误。原因很简单,A()调用了A(int a),而A(int a)在执行时要调用A(),A()执行时又会调用A(int a),这样层层调用,没完没了,不能实现。
9、单列模式。单列模式是指,对于某个类,别的类只允许创建该类有一个对象。实现的代码如下:

 类A的构造方法必须为private,否则就无法限制对象的个数了。getInstance()是静态工厂方法。具体的流程就不说了,是挺简单的,要付诸文字却不易。后面的打印是“true”,即表明上是创建了两个引用指向两个对象,但两个引用指向的是同一个对象,整体下来,还是只创建了一个对象。
10、程序加载过程。在一个java源文件中,有父类、有子类、主类,每个类中又有不同的成分(成分:静态语句、非静态语句、构造方法等),执行的顺序是怎样呢?概述如下:
(1)、先加载要创建对象的类及其直接和间接父类;(所以主类一般先加载)
(2)、加载类时,同时会加载静态成员,主要是静态成语的初始化,执行静态语句(static{});(静态成语是属于类的,某些语句要以之为基础,故先加载)
(3)、完成(1)后,开始创建对象。首先会加载非静态成员,主要是非静态成员变量的初始化,非静态语句的执行(没有static修饰的部分);
(4)、最后执行构造方法,执行完后,对象生成。