system.out.println("wind2.play()");
// redefine interface method:
public static final note
private int value;
“多形性”(polymorphism)从另一个角度将接口从具体的实施细节中分离出来,亦即实现了“是什么”与“怎样做”两个模块的分离利用多形性的概念,代码的组织以及可读性均能获得改善此外,还能创建“易于扩展”的程序无论在项目的创建过程中,还是在需要加入新特性的时候,它们都可以方便地“成长”
}
middlec = new note(0),
} // etc.
//java主要特点 because they have the same interface:
tune(frenchhorn);
public void play(note n) {
上述程序最令人迷惑不解的地方全与早期绑定有关,因为在只有一个instrument句柄的前提下,编译器不知道具体该调用哪个方法
}
}
private note2(int val) { value = val; }
为什么要把一个方法声明成final呢?正如上一章指出的那样,它能防止其他人覆盖那个方法但也许更重要的一点是,它可有效地“关闭”动态绑定,或者告诉编译器不需要进行动态绑定这样一来,编译器就可为final方法调用生成效率更高的代码
7.1.1 为什么要上溯造Java工作好不好找型
}
public void play(note2 n) {
它接收instrument句柄所以在这种情况下,编译器怎样才能知道instrument句柄指向的是一个wind,而不是一个brass或stringed呢?编译器无从得知为了深入了理解这个问题,我们有必要探讨一下“绑定”这个主题
i.play(note.middlec);
public void play(note2 n) {
system.out.println("wind.play()");
public static void tune(wind2 i) {
// ...
}
stringed2 violin = new stringed2();
system.out.println("java历史起源brass2.play()");
// wind objects are instruments
class wind2 extends instrument2 {
这正是“多形性”大显身手的地方然而,大多数程序员(特别是有程序化编程背景的)对于多形性的工作原理仍然显得有些生疏
在这一章中,大家要由浅入深地学习有关多形性的问题(也叫作动态绑定、推迟绑定或者运行期绑定)同时举一些简单的例子,其中所有无关的部分都已剥除,只保留与多形性有关的代码
i.play(note2.middlec);
class stringed2 extends instrument2 {
}
system.out.println("instrument.play()");
pjavaublic static final note2
}
public static void main(string[] args) {
在面向对象的程序设计中,有一个经典的“形状”例子由于它很容易用可视化的形式表现出来,所以经常都用它说明问题但很不幸的是,它可能误导初学者认为oop只是为图形化编程设计的,这种认识当然是错误的
private note(int val) { value = val; }
7.1 上溯造型
public static void tune(instrument i) {
这样做当然行得通,但却存在一个极大的弊端:必须为每种新增的instrument2类编写与类紧密相关的方法这意味着第一次就要求多得多Java培训的编程量以后,假如想添加一个象tune()那样的新方法或者为instrument添加一个新类型,仍然需要进行大量编码工作此外,即使忘记对自己的某个方法进行过载设置,编译器也不会提示任何错误这样一来,类型的整个操作过程就显得极难管理,有失控的危险
这个程序看起来也许显得有些奇怪为什么所有人都应该有意忘记一个对象的类型呢?进行上溯造型时,就可能产生这方面的疑惑而且如果让tune()简单地取得一个wind句柄,将其作为自己的自变量使用,似乎会更加简单、直观得多但要注意:假如那样做,就需为系统内instrument的每种类型写一个全新的tune()假设按照前面的推论,加入stringed(弦乐)和brass(铜管)这两种iJava学习nstrument(乐器):
class wind extends instrument {
public static void main(string[] args) {
对于music.java的困难性,可通过运行程序加以体会输出是wind.play()这当然是我们希望的输出,但它看起来似乎并不愿按我们的希望行事请观察一下tune()方法:
7.2 深入理解
i.play(note2.middlec);
class brass2 extends instrument2 {
public static void tune(brass2 i) {
解决的方法就是“后期绑定”,它意味着绑定在运行期间进行,以对象的类型为基础后期绑定也叫作“动态绑Java培训定”或“运行期绑定”若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体不同的语言对后期绑定的实现方法是有所区别的但我们至少可以这样认为:它们都要在对象中安插某些特殊类型的信息
}
cflat = new note2(2);
public void play(note2 n) {
public void play(note n) {
java中绑定的所有方法都采用后期绑定技术,除非一个方法已被声明成final这意味着我们通常不必决定是否应进行后期绑定――它是自动发生的
}
wind flute 主要优点= new wind();
csharp = new note2(1),
class note2 {
system.out.println("instrument2.play()");
public class music2 {
// inheritance & upcasting
} // etc.
class instrument2 {
}
i.play(note.middlec);
}
public class music {
在第6章,大家已知道可将一个对象作为它自己的类型使用,或者作为它的基础类型的一个对象使用取得一个对象句柄,并将其作为基础类型句柄使用的行为就叫作“上溯造型”――因为继承树的画法是基础类位于最上方
} ///:~
}
但假如只写一Java学习资料个方法,将基础类作为自变量或参数使用,而不是使用那些特定的衍生类,岂不是会简单得多?也就是说,如果我们能不顾衍生类,只让自己的代码与基础类打交道,那么省下的工作量将是难以估计的
其中,方法music.tune()接收一个instrument句柄,同时也接收从instrument衍生出来的所有东西当一个wind句柄传递给tune()的时候,就会出现这种情况此时没有造型的必要这样做是可以接受的;instrument里的接口必须存在于wind中,因为wind是从instrument里继承得到的从wind向instrument的上溯造型可能“缩小”那个接口,但不可能把它变得比instrument的完整接口还要小Java的优点有哪些
middlec = new note2(0),
tune(flute); // no upcasting
通过合并各种特征与行为,封装技术可创建出新的数据类型通过对具体实施细节的隐藏,可将接口与实施细节分离,使所有细节成为“private”(私有)这种组织方式使那些有程序化编程背景人感觉颇为舒适但多形性却涉及对“类型”的分解通过上一章的学习,大家已知道通过继承可将一个对象当作它自己的类型或者它自己的基础类型对待这种能力是十分重要的,因为多个类型(从相同的基础类型中衍生出来)可被当作同一种类型对待利用具有多形性的方法调用,一种类型可将自己与另一种相似的类型区分开,只要它们都是从相同的基础类型中衍生出来的这种区分是通过各java学习资料种方法在行为上的差异实现的,可通过基础类实现对那些方法的调用
package c07;
知道java里绑定的所有方法都通过后期绑定具有多形性以后,就可以相应地编写自己的代码,令其与基础类沟通此时,所有的衍生类都保证能用相同的代码正常地工作或者换用另一种方法,我们可以“将一条消息发给一个对象,让对象自行判断要做什么事情”
}
//: music2.java
7.2.2 产生正确的行为
wind2 flute = new wind2();
public static void tune(instrument i) {
// ...
}
csharp = new note(1),
}
system.out.println("stringed2.play()");java编程思想
“对于面向对象的程序设计语言,多型性是第三种最基本的特征(前两种是数据抽象和继承”
}
}
cflat = new note(2);
i.play(note2.middlec);
tune(violin);
private int value;
brass2 frenchhorn = new brass2();
//: music.java
}
public void play(note2 n) {
将一个方法调用同一个方法主体连接到一起就称为“绑定”(binding)若在程序运行以前执行绑定(由编译器和链接程序,如果有的话),就叫作“早期绑定”大家以前或许从未听说过这个术语,因为它在任何程序化语言里都是不可能的c编译器只有一种方法调用,那就是“早期绑定Java的优点有哪些”
查看本文来源
}
class instrument {
7.2.1 方法调用的绑定
} ///:~
public static void tune(stringed2 i) {
但这样做也会遇到一个问题,如下例所示(若执行这个程序遇到麻烦,请参考第3章的3.1.2小节“赋值”):
tune(flute); // upcasting
class note {
// overloading instead of upcasting
白癜风传染白癜风医院