Java三大特性
封装、继承、多态是面向对象程序设计语言的三种基本特征。
封装是通过合并特征和行为来创建新的数据类型,再配合权限控制把接口和实现分离。在此基础上为了便于代码的复用又产生了继承,子类通过extends关键字继承来自于父类的非私有成员变量和方法,同时可以扩展自己的成员变量和方法。因为继承允许将多种从同一基类导出的类型视为基类类型来处理,也就是一份代码可以毫无差别的运行在不同类别之上,这就形成了多态,多态可以消除类型之间的耦合关系。
方法的调用绑定
将一个方法调用同一个方法主体关联起来被称作绑定,在编译时绑定称作前期绑定,在运行时绑定称作后期绑定。
//polymorphism/shape/Shape.java
class Shape {
public void draw() {}
public void erase() {}
}
class Circle extends Shape {
@Override
public void draw() { System.out.println("Circle.draw()"); }
@Override
public void erase() { System.out.println("Circle.erase"); }
}
class Square extends Shape {
@Override
public void draw() { System.out.println("Square.draw()"); }
@Override
public void erase() { System.out.println("Square.erase"); }
}
class Triangle extends Shape {
@Override
public void draw() { System.out.println("Triangle.draw()"); }
@Override
public void erase() { System.out.println("Triangle.erase"); }
}
public class RandomShapeGenerator {
private Random rand = new Random(47);
public Shape next() {
switch (rand.nextInt(3)) {
case 0: return new Circle();
case 1: return new Square();
case 2: return new Triangle();
}
return new Shape();
}
}
//polymorphism/shape/Shapes.java
public class Shapes {
private static RandomShapeGenerator gen =
new RandomShapeGenerator();
public static void main(String[] args) {
Shape[] s = new Shape[9];
for (int i = 0; i < s.length; i++) {
s[i] = gen.next();
}
for (Shape shp : s) {
shp.draw();
}
}
}/*output
Triangle.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Circle.draw()
*/
每次调用next()方法时可以随机生成一个Shape对象返回一个引用,在return语句里使用到向上转型。main()方法包含一个Shape数组,我们只知道拥有一些Shape,除此之外不会知道更具体的内容,然而在遍历数组调用draw()方法时,却发生了与特定类型有关的特定行为。这是由后期绑定实现的,其含义就是在运行时根据对象的类型进行绑定,编译器一直不知道对象的类型,但是方法的调用机制却能找到正确的方法体。Java中除了static方法、private方法、final方法外都是后期绑定。
继承与组合
通过对成员类型使用继承技术的添加技巧,可以在运行时改变那些成员对象的类型和行为,因此,可以在运行时改变组合而成的对象的行为。所以组合比继承更灵活,所以要优先选择组合。
class Actor {
public void act() {}
}
class HappyActor extends Actor {
public void act() { System.out.println("HappyActor"); }
}
class SadActor extends Actor {
public void act() { System.out.println("SadActor"); }
}
class Stage {
private Actor actor = new HappyActor();
public void change() { actor = new SadActor(); }
public void performPlay() { actor.act(); }
}
public class Transmogrify {
public static void main(String[] args) {
Stage stage = new Stage();
stage.performPlay();
stage.change();
stage.performPlay();
}
}/*output
HappyActor
SadActor
*/
Stage对象包含Actor的引用,而引用可以在运行时与另一个不同的对象重新绑定起来,所以SadActor对象的引用可以在actor中被替代,然后performPlay()产生的行为也随之改变。