知道Java里绑定的所有体例都经由过程后期绑定具有多形性往后,就可以响应地编写自己的代码,令其与基本类沟通。此时,所有的衍生类都保证能用不异的代码正常地工作。或者换用另一种体例,我们可以“将一条动静发给一个对象,让对象自行判定要做什么工作。”
: a2 T; w: w: W/ E 在面向对象的轨范设计中,有一个经典的“外形”例子。因为它很轻易用可视化的形式默示出来,所以经常都用它声名问题。但很不幸的是,它可能误导初学者认为OOP只是为图形化编程设计的,这种熟悉当然是错误的。
+ w* x6 m$ I4 g6 {3 S I9 m4 k 外形例子有一个基本类,名为Shape;此外还有年夜量衍生类型:Circle(圆形),Square(方形),Triangle(三角形)等等。巨匠之所以喜欢这个例子,因为很轻易理解“圆属于外形的一种类型”等概念。下面这幅担任图向我们展示了它们的关系:
& t! S% x. ~, b9 b4 L9 [6 | 上溯造型可用下面这个语句简单地默示出来:
' A/ s' G/ O1 p" S( r. v- s! p' s Shape s = new Circle();
& o& C* S2 Z8 ?: F) e8 o: q& A 在这里,我们建树了Circle对象,并将结不美观句柄当即赋给一个Shape。这概况看起来似乎属于错误操作(将一种类型分配给另一个),但现实是完全可行的——因为按照担任关系,Circle属于Shape的一种。是以编译器认可上述语句,不会向我们提醒一条犯错动静。2 K3 P! M+ D. S/ B4 p
当我们挪用其一一个基本类体例时(已在衍生类里笼盖):2 P9 g5 _" k! ]* d
s.draw();$ o5 Y4 b/ `5 R3 ?2 W( R8 A5 {1 [
同样地,巨匠也许认为会挪用Shape的draw(),因为这事实下场是一个Shape句柄。那么编译器若何才能知道该做其他任何工作呢?但此时现实挪用的是Circle.draw(),因为后期绑定已经介入若干好多形性)。$ x) g2 T. Z/ Y& Z* I; e
下面这个例子年夜一个稍微分歧的角度说了然问题:
6 W/ V9 g# c9 C8 o8 P7 [6 e //: Shapes.java6 }& Z2 y; `$ J9 {$ w+ U3 m
// Polymorphism in Java+ I( g9 a9 T2 ?9 H9 E
class Shape {9 J, ] Y1 r8 m
void draw() {}, D5 f) b8 o; c8 u
void erase() {}% Q1 c0 [" K$ e) y5 d
}0 T% I5 j0 r3 Q7 A; U" h4 P; [
class Circle extends Shape {5 g6 F0 v# g$ L, H( ]. H
void draw() {
2 U' @3 {7 E: k2 \7 w' ` System.out.println("Circle.draw()");
! }, h" v8 k# K6 b }4 _5 \% c9 o# O: ^: K
void erase() {
& j u/ Y [$ e& J; N, s System.out.println("Circle.erase()");
4 K }( o% ?4 @; p4 J }
* R/ Z; \) ]- F a8 Q }. I$ o1 h" U+ F5 ?+ b
class Square extends Shape {
D) v! b, E. x6 d1 ?2 t void draw() {
% H6 S( [; F7 Q% q' N4 j System.out.println("Square.draw()");0 Q% d: i* y9 }+ _
}: O* V3 e, K! t8 j6 P b( Q9 B
void erase() {1 ^) _" g0 j) o6 X" B4 Q9 j$ Y9 w/ r
System.out.println("Square.erase()");
. k; G$ h% H6 V }
3 W( ^7 N @0 G9 L; j3 G }
5 Z3 w( s* Z( |# h0 u" M" S1 \ class Triangle extends Shape {& O. Q+ w2 N; a- P
void draw() {5 B4 h4 p. b# r% f8 R" ^7 E
System.out.println("Triangle.draw()");: k$ _3 Z% p4 \5 Q2 ^
} |