分享
 
 
 

[学习笔记]Thinking in Java (the 2nd edition) Study Note (2)

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

第4章 初始化和清除

“随着计算机的进步,‘不安全’的程序设计已成为造成编程代价高昂的罪魁祸首之一。”

“初始化”和“清除”是这些安全问题的其中两个。

4.1 构造函数

<1>不能用返回值来区分不同的函数,比如:

void f() {}

int f() {}

我们可能调用一个方法,同时忽略返回值;通常把这称为“为它的副作用去调用一个方法”,因为我们关心的不是返回值,

而是方法调用的其他效果。所以假如我们象下面这样调用方法:

f();

Java怎样判断f()的具体调用方式呢?而且别人如何识别并理解代码呢?由于存在这一类的问题,所以不能根据返回值

类型来区分重载的方法。

<2>下面这一行:

new Bird();

它的作用是新建一个对象,并调用默认构建器——即使尚未明确定义一个象这样的构建器。若没有它,就没有方法可以调用,

无法构建我们的对象。然而,如果已经定义了一个构建器(无论是否有自变量),编译程序都不会帮我们自动合成一个:

class Bush {

Bush(int i) {}

Bush(double d) {}

}

现在,假若使用下述代码:

new Bush();

编译程序就会报告自己找不到一个相符的构建器。就好象我们没有设置任何构建器,编译程序会说:“你看来似乎需要一个

构建器,所以让我们给你制造一个吧。”但假如我们写了一个构建器,编译程序就会说:“啊,你已写了一个构建器,所以

我知道你想干什么;如果你不放置一个默认的,是由于你打算省略它。”

4.2 垃圾收集

finalize()最有用处的地方之一是观察垃圾收集的过程。下面这个例子向大家展示了垃圾收集所经历的过程,并对前面的

陈述进行了总结。

//: Garbage.java

// Demonstration of the garbage

// collector and finalization

class Chair {

static boolean gcrun = false;

static boolean f = false;

static int created = 0;

static int finalized = 0;

int i;

Chair() {

i = ++created;

if(created == 47)

System.out.println("Created 47");

}

protected void finalize() {

if(!gcrun) {

gcrun = true;

System.out.println(

"Beginning to finalize after " +

created + " Chairs have been created");

}

if(i == 47) {

System.out.println(

"Finalizing Chair #47, " +

"Setting flag to stop Chair creation");

f = true;

}

finalized++;

if(finalized >= created)

System.out.println(

"All " + finalized + " finalized");

}

}

public class Garbage {

public static void main(String[] args) {

if(args.length == 0) {

System.err.println("Usage: \n" +

"java Garbage before\n or:\n" +

"java Garbage after");

return;

}

while(!Chair.f) {

new Chair();

new String("To take up space");

}

System.out.println(

"After all Chairs have been created:\n" +

"total created = " + Chair.created +

", total finalized = " + Chair.finalized);

if(args[0].equals("before")) {

System.out.println("gc():");

System.gc();

System.out.println("runFinalization():");

System.runFinalization();

}

System.out.println("bye!");

if(args[0].equals("after"))

System.runFinalizersOnExit(true);

}

} ///:~

4.3 对象数组的写法

Integer[] b = new Integer[] {

new Integer(1),

new Integer(2),

new Integer(3), //最后的","是可以存在的

};

第5章 隐藏实施过程

“进行面向对象的设计时,一项基本的考虑是:如何将发生变化的东西与保持不变的东西分隔开。”

第6章 类再生

“Java引人注目的一项特性是代码的重复使用或者再生。但最具革命意义的是,除代码的复制和修改以外,我们还能做多

得多的其他事情。”

在这一章里,我们将介绍两个达到这一目标[即代码复用]的方法。第一个最简单:在新类里简单地创建原有类的对象。

我们把这种方法叫作“合成”,因为新类由现有类的对象合并而成。我们只是简单地重复利用代码的功能,而不是采用它的

形式。第二种方法则显得稍微有些技巧。它创建一个新类,将其作为现有类的一个“类型”。我们可以原样采取现有类的形

式,并在其中加入新代码,同时不会对现有的类产生影响。这种魔术般的行为叫作“继承”(Inheritance)。

6.1 继承:基础类的初始化

//: Cartoon.java

// Constructor calls during inheritance

class Art {

Art() {

System.out.println("Art constructor");

}

}

class Drawing extends Art {

Drawing() {

System.out.println("Drawing constructor");

}

}

public class Cartoon extends Drawing {

Cartoon() {

System.out.println("Cartoon constructor");

}

public static void main(String[] args) {

Cartoon x = new Cartoon();

}

} ///:~

该程序的输出显示了自动调用:

Art constructor

Drawing constructor

Cartoon constructor

这表明:在调用子类的时候 ,父类的构造方法均被调用了一次

--含有自变量的构建器--

上述例子有自己默认的构建器;也就是说,它们不含任何自变量。编译器可以很容易地调用它们,因为不存在具体传递

什么自变量的问题。如果类没有默认的自变量,或者想调用含有一个自变量的某个基础类构建器,必须明确地编写对基

础类的调用代码。这是用super关键字以及适当的自变量列表实现的:

class Art {

Art(int i) {

System.out.println("Art constructor");

}

}

class Drawing extends Art {

Drawing() {

super(1) ;

System.out.println("Drawing constructor");

}

}

public class Cartoon extends Drawing {

Cartoon() {

super(11) ;

//缺少该句,将编译不过,也就是说,你必须显式的提供基类的构造方法,除非基类提供默认无参构造函数

System.out.println("Cartoon constructor");

}

public static void main(String[] args) {

Cartoon x = new Cartoon();

}

} ///:~

6.2 积累开发

大家要记住这样一个重点:程序开发是一个不断递增或者累积的过程,就象人们学习知识一样。当然可根据要求进行

尽可能多的分析,但在一个项目的设计之初,谁都不可能提前获知所有的答案。如果能将自己的项目看作一个有机的、

能不断进步的生物,从而不断地发展和改进它,就有望获得更大的成功以及更直接的反馈。

6.3 final

<1>.final数据

对于基本数据类型,final会将值变成一个常数;但对于对象句柄,final会将句柄变成一个常数。进行声明时,必须

将句柄初始化到一个具体的对象。而且永远不能将句柄变成指向另一个对象。然而,对象本身是可以修改的。Java对此

未提供任何手段,可将一个对象直接变成一个常数(但是,我们可自己编写一个类,使其中的对象具有“常数”效果)。

这一限制也适用于数组,它也属于对象。

<2>.空白final

现在强行要求我们对final进行赋值处理——要么在定义字段时使用一个表达式,要么在每个构建器中。这样就可以确保

final字段在使用前获得正确的初始化。

<3>.final方法

之所以要使用final方法,可能是出于对两方面理由的考虑。第一个是为方法“上锁”,防止任何继承类改变它的本来含

义。设计程序时,若希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写,就可以采取这种做法。采用

final方法的第二个理由是程序执行的效率。将一个方法设成final后,编译器就可以把对那个方法的所有调用都置入

“嵌入”调用里。

<4>.final类

如果说整个类都是final(在它的定义前冠以final关键字),就表明自己不希望从这个类继承,或者不允许其他任何人

采取这种操作。换言之,出于这样或那样的原因,我们的类肯定不需要进行任何改变;或者出于安全方面的理由,我们不

希望进行子类化(子类处理)。除此以外,我们或许还考虑到执行效率的问题,并想确保涉及这个类各对象的所有行动都

要尽可能地有效。

第7章 多形性

“对于面向对象的程序设计语言,多型性是第三种最基本的特征(前两种是数据抽象和继承)。”

上溯造型可用下面这个语句简单地表现出来:

Shape s = new Circle();

在这里,我们创建了Circle对象,并将结果句柄立即赋给一个Shape。这表面看起来似乎属于错误操作(将一种类型分配

给另一个),但实际是完全可行的——因为按照继承关系,Circle属于Shape的一种。因此编译器认可上述语句,不会向

我们提示一条出错消息。

当我们调用其中一个基础类方法时(已在衍生类里覆盖):

s.draw();

同样地,大家也许认为会调用Shape的draw(),因为这毕竟是一个Shape句柄。那么编译器怎样才能知道该做其他任何事

情呢?但此时实际调用的是Circle.draw(),因为后期绑定已经介入(多形性)。

7.1 覆盖与重载

覆盖指 子类的参数名和类型与父类的一一对应

重载指 方法重载,但没有覆盖

如果从一个抽象类继承,而且想生成新类型的一个对象,就必须为基础类中的所有抽象方法提供方法定义。如果不这样做

(完全可以选择不做),则衍生类也会是抽象的,而且编译器会强迫我们用abstract关键字标志那个类的“抽象”本质。即

使不包括任何abstract方法,亦可将一个类声明成“抽象类”。

7.2 接口

“interface”(接口)关键字使抽象的概念更深入了一层。我们可将其想象为一个“纯”抽象类。它允许创建者规定一个类

的基本形式:方法名、自变量列表以及返回类型,但不规定方法主体。接口也包含了基本数据类型的数据成员,但它们都

默认为static和final。接口只提供一种形式,并不提供实施的细节。

接口这样描述自己:“对于实现我的所有类,看起来都应该象我现在这个样子”。因此,采用了一个特定接口的所有代码都

知道对于那个接口可能会调用什么方法。这便是接口的全部含义。所以我们常把接口用于建立类和类之间的一个“协议”。

7.3 常数分组

由于置入一个接口的所有字段都自动具有static和final属性,所以接口是对常数值进行分组的一个好工具,它具有与C或

C++的enum非常相似的效果。如下例所示:

7.4 内部类和上溯造型

迄今为止,内部类看起来仍然没什么特别的地方。毕竟,用它实现隐藏显得有些大题小做。Java已经有一个非常优秀的隐藏

机制——只允许类成为“友好的”(只在一个包内可见),而不是把它创建成一个内部类。

小结

“多形性”意味着“不同的形式”。在面向对象的程序设计中,我们有相同的外观(基础类的通用接口)以及使用那个外观的不

同形式:动态绑定或组织的、不同版本的方法。

通过这一章的学习,大家已知道假如不利用数据抽象以及继承技术,就不可能理解、甚至去创建多形性的一个例子。多形性是

一种不可独立应用的特性(就象一个switch语句),只可与其他元素协同使用。我们应将其作为类总体关系的一部分来看待。

人们经常混淆Java其他的、非面向对象的特性,比如方法过载等,这些特性有时也具有面向对象的某些特征。但不要被愚弄:

如果以后没有绑定,就不成其为多形性。

为使用多形性乃至面向对象的技术,特别是在自己的程序中,必须将自己的编程视野扩展到不仅包括单独一个类的成员和消息,

也要包括类与类之间的一致性以及它们的关系。尽管这要求学习时付出更多的精力,但却是非常值得的,因为只有这样才可真

正有效地加快自己的编程速度、更好地组织代码、更容易做出包容面广的程序以及更易对自己的代码进行维护与扩展。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有