多态前提:
继承关系;
方法重写;
向上转型(父类引用指向子类对象)
成员变量 编译看左边(父类),运行看左边(父类)
成员方法 编译看左边(父类),运行看右边(子类)动态绑定
静态方法 编译看左边(父类),运行看左边(父类)
静态和类相关,算不上重写。访问还是左边
只有非静态的成员方法,编译看左边,运行看右边
8.1 再论向上转型
package chapter8polymorphism.music;
public enum Note{ // 乐符
MIDDLE_C,C_SHARP,B_FLAT
}
package chapter8polymorphism.music;
class Instrument{
public void play(Note n){
System.out.println("Instrument.play()");
}
}
package chapter8polymorphism.music;
public class Wind extends Instrument {
// 重新定义 接口方法
public void play(Note n) {
System.out.println("Wind.play()" + n);
}
}
package chapter8polymorphism.music;
public class Music {
public static void tune(Instrument i){
i.play(Note.MIDDLE_C);
}
public static void main(String[] args) {
Wind flute = new Wind();
tune(flute); //向上转型
}
}
8.1.1 忘记对象类型
8.2 转机
方法调用绑定
绑定: 方法调用 和 方法主体 关联
前期绑定: C 程序执行前进行绑定
除了static 和final(private属于final方法)方法外,其他所有方法 都是后期绑定
方法为final : 1.防止覆盖 2. 有效“关闭”动态绑定
8.2.2 产生正确的行为
package chapter8polymorphism;
import chapter8polymorphism.Shape.RandomShapeGenerator;
import chapter8polymorphism.Shape.Shape;
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(); // gen.next() 返回 向上转型
for (Shape shp :s)
shp.draw(); // 多态方法调用
}
} /*
Triangle.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Circle.draw()
*/
package chapter8polymorphism.Shape;
import java.util.Random;
public class RandomShapeGenerator { // factory
private Random random = new Random(47);
public Shape next(){
switch (random.nextInt(3)){
default:
case 0: return new Circle();
case 1: return new Square();
case 2: return new Triangle();
}
}
}
package chapter8polymorphism.Shape;
public class Shape {
public void draw(){}
public void erase(){}
}
package chapter8polymorphism.Shape;
public class Circle extends Shape {
public void draw(){
System.out.println("Circle.draw()");
}
public void erase(){
System.out.println("Circle.erase()");
}
}
package chapter8polymorphism.Shape;
public class Square extends Shape{
public void draw(){
System.out.println("Square.draw()");
}
public void erase(){
System.out.println("Square.erase()");
}
}
package chapter8polymorphism.Shape;
public class Triangle extends Shape{
public void draw(){
System.out.println("Triangle.draw()");
}
public void erase(){
System.out.println("Triangle.erase()");
}
}
可扩展性
class InstrumentGenerator2 {
java.util.Random gen = new java.util.Random(47);
Class<?> instruments[] = {
Wind.class,
Percussion.class,
Stringed.class,
Brass.class,
Woodwind.class,
Electronic.class,
};
public Instrument next() {
try {
int idx = Math.abs(gen.nextInt(instruments.length));
return (Instrument) instruments[idx].newInstance(); // 创建实例
} catch (Exception e) {
throw new RuntimeException("Cannot Create", e);
}
}
}
public class E08_RandomInstruments2 {
public static void main(String[] args) {
InstrumentGenerator2 gen = new InstrumentGenerator2();
for (int i = 0; i < 20; i++)
System.out.println(gen.next());
}
}
package chapter8polymorphism.Rodent;
class Rodent {
void eat() {
System.out.println("Rodent.eat()");
}
}
class Mouse extends Rodent {
void eat() {
System.out.println("Mouse.eat()");
}
}
class Gerbil extends Rodent { // 鼹鼠
void eat() {
System.out.println("Gerbil.eat()");
}
}
class Hamste extends Rodent { // 大颊鼠
void eat() {
System.out.println("Hamste.eat()");
}
}
//public class E09_Rodent {
// public static void main(String[] args) {
// Rodent[] rodents = {
// new Mouse(),
// new Gerbil(),
// new Hamste(),
// };
// for (Rodent rodent:rodents)
// rodent.eat();
// }
//}
/* Output
Mouse.eat()
Gerbil.eat()
Hamste.eat()
*/
public class E09_Rodent {
public static void main(String[] args) {
Class<?> rodents[] = {
Mouse.class,
Gerbil.class,
Hamste.class,
};
for (int i = 0; i < rodents.length; i++) {
try {
Rodent rodent = (Rodent)rodents[i].newInstance();
rodent.eat();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package chapter8polymorphism.Rodent;
class TwoMethod{
void firstMethod(){
System.out.println("TwoMethod.firstMethod()");
secondMethod();
}
void secondMethod(){
System.out.println("TwoMethod.secondMethod()");
}
}
class FromTwoMethod extends TwoMethod{
void secondMethod(){
System.out.println("FromTwoMethod.secondMethod()");
}
}
public class E10_Method {
public static void main(String[] args) {
TwoMethod fromTwoMethod = new FromTwoMethod();
fromTwoMethod.firstMethod();
}
}
/* Output
TwoMethod.firstMethod()
FromTwoMethod.secondMethod()
*/
8.2.4 缺陷: “覆盖”私有方法
静态方法和类关联,与单个对象无关联。
package chapter8polymorphism;
public class PrivateOverride {
private void f(){ // private 方法 自动认为 final方法,对导出类屏蔽
System.out.println("private f()");
}
public static void main(String[] args) {
PrivateOverride po = new Derived();
po.f(); // 只有 非private方法 才可以被覆盖
}
}
class Derived extends PrivateOverride{
public void f(){ // 全新的方法 对于基类的private 方法,最好采用不同的名字
System.out.println("public f()");
}
}
/* Output
private f()
*/
8.2.5 缺陷: 域与静态方法
package chapter8polymorphism;
class Super {
public int field = 0;
public int getField() {
return field;
}
}
class Sub extends Super {
public int field = 1;
public int getField() {
return field;
}
public int getSuperField() {
return super.field;
}
}
public class FieldAccess {
public static void main(String[] args) {
Super sup = new Sub(); // 向上转型 字段访问操作 由编译器解析。不是多态。
System.out.println("sup.field = " + sup.field + " .sup.getField() = " + sup.getField());
Sub sub = new Sub(); // Super.field sub.field 分配了不同的存储空间, Sub实际包括两个field的域:它自己和它从Super得到,
// 默认字段并非Super版本的field.必须显式指明super.field
// 实践不存在,通常会将所有字段设置成private.不能直接访问。
System.out.println("sub.field = " + sub.field + " .sub.getField() = " + sub.getField() + ", sub.getSuperField() = " + sub.getSuperField());
}
}
/* Output 访问字段 是在编译期进行解析
sup.field = 0 .sup.getField() = 1
sub.field = 1 .sup.getField() = 1, sub.getSuperField() = 0
*/
ackage chapter8polymorphism;
class StaticSuper{
public static String staticGet(){
return "Base staticGet()";
}
public String dynamicGet(){
return "Base dynamicGet()";
}
}
class StaticSub extends StaticSuper{
public static String staticGet(){
return "Derived staticGet()";
}
public String dynamicGet(){
return "Derived dynamicGet()";
}
}
public class StaticPolymorphism {
public static void main(String[] args) {
StaticSuper sup = new StaticSub(); // Upcast
System.out.println(sup.staticGet());
System.out.println(sup.dynamicGet());
}
}
/* Output
Base staticGet()
Derived dynamicGet()
*/
8.3 构造器和多态
构造器不具有多态性,实际是隐式static方法
1.调用基类构造方法
2.按声明顺序调用成员的初始化方法
3.调用子类构造方法的主体
静态字段
静态代码块
字段
初始化块
构造方法
字段
初始化块
构造方法
package chapter8polymorphism;
import chapter7reusing.Chess;
class Meal{
Meal(){
System.out.println("Meal()");
}
}
class Bread{
Bread(){
System.out.println("Bread()");
}
}
class Cheese{
Cheese(){
System.out.println("Cheese()");
}
}
class Lettuce{
Lettuce(){
System.out.println("Lettuce()");
}
}
class Lunch extends Meal{
Lunch(){
System.out.println("Lunch()");
}
}
class PortableLunch extends Lunch{
PortableLunch(){
System.out.println("PortableLunch()");
}
}
public class Sandwich extends PortableLunch {
private Bread b = new Bread();
private Cheese c = new Cheese();
private Lettuce l = new Lettuce();
public Sandwich(){
System.out.println("Sandwich()");
}
public static void main(String[] args) {
new Sandwich();
}
}
/* Output
Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
*/
8.3.2 继承与清理
销毁顺序 按照 创建的逆序 进行
package chapter8polymorphism;
class Characteristic{
private String s;
Characteristic(String s){
this.s = s;
System.out.println("Characteristic " + s);
}
protected void dispose(){
System.out.println("disposing Characteristic " + s);
}
}
class Description {
private String s;
Description(String s){
this.s = s;
System.out.println("Creating Description " + s);
}
protected void dispose(){
System.out.println("disposing Description " + s);
}
}
class LivingCreature{
private Characteristic p = new Characteristic("is alive");
private Description t = new Description("Basic Living Creature");
LivingCreature(){
System.out.println("LivingCreature()");
}
protected void dispose(){
System.out.println("LivingCreature dispose");
t.dispose();
p.dispose();
}
}
class Animal extends LivingCreature{
private Characteristic p = new Characteristic("has heart");
private Description t = new Description("Animal not Vegetable");
Animal(){
System.out.println("Animal()");
}
protected void dispose(){
System.out.println("Animal dispose");
t.dispose();
p.dispose();
super.dispose();
}
}
class Amphibian extends Animal{
private Characteristic p = new Characteristic("can live in water");
private Description t = new Description("Both water and land");
Amphibian(){
System.out.println("Amphibian()");
}
protected void dispose(){
System.out.println("Animal dispose");
t.dispose();
p.dispose();
super.dispose();
}
}
public class Frog extends Amphibian{
private Characteristic p = new Characteristic("Croaks");
private Description t = new Description("Eats Bugs");
Frog(){
System.out.println("Frog()");
}
protected void dispose(){
System.out.println("Frog dispose");
t.dispose();
p.dispose();
super.dispose();
}
public static void main(String[] args) {
Frog frog = new Frog();
System.out.println("Bye!");
frog.dispose();
}
}
/* Output
Characteristic is alive
Creating Description Basic Living Creature
LivingCreature()
Characteristic has heart
Creating Description Animal not Vegetable
Animal()
Characteristic can live in water
Creating Description Both water and land
Amphibian()
Characteristic Croaks
Creating Description Eats Bugs
Frog()
Bye!
Frog dispose
disposing Description Eats Bugs
disposing Characteristic Croaks
Animal dispose
disposing Description Both water and land
disposing Characteristic can live in water
Animal dispose
disposing Description Animal not Vegetable
disposing Characteristic has heart
LivingCreature dispose
disposing Description Basic Living Creature
disposing Characteristic is alive
*/
关于共享对象 引用计数 确定清理
package chapter8polymorphism;
class Shared{
private int refcount = 0;
private static long counter = 0; // Shared实例数量 long 不是int 防止溢出
private final long id = counter++; // final 不期望对象生命周期内改变。
public Shared(){
System.out.println("Creating " + this );
}
public void addRef(){refcount++;}
protected void dispose(){
if (--refcount == 0) // 跟踪引用计数 确定何时清理
System.out.println("Disposing " + this);
}
public String toString(){
return "shared " + id;
}
}
class Composing{
private Shared shared;
private static long counter = 0;
private final long id =counter++;
public Composing(Shared shared){
System.out.println("Creating " + this);
this.shared = shared;
this.shared.addRef(); // 增加引用
}
protected void dispose(){
System.out.println("disposing " + this);
shared.dispose();
}
public String toString(){
return "Composing " + id;
}
}
public class ReferenceCounting {
public static void main(String[] args) {
Shared shared = new Shared();
Composing[] composing = {
new Composing(shared),
new Composing(shared),
new Composing(shared),
new Composing(shared),
new Composing(shared),
};
for (Composing c: composing)
c.dispose();
}
}
/*
Creating shared 0
Creating Composing 0
Creating Composing 1
Creating Composing 2
Creating Composing 3
Creating Composing 4
disposing Composing 0
disposing Composing 1
disposing Composing 2
disposing Composing 3
disposing Composing 4
Disposing shared 0
*/
8.3.3 构造器内部的多态方法的行为
package chapter8polymorphism;
class Glyph{ // 石雕符号; 象形文字;
void draw(){
System.out.println("Glyph.draw()");
}
Glyph(){
System.out.println("Glyph() before drwa()");
draw();
System.out.println("Glyph() after drwa()");
}
}
class RoundGlyph extends Glyph{
private int radius = 1;
RoundGlyph(int r){
radius = r;
System.out.println("RoundGlyph.RoundGlyph().radius = " + radius);
}
void draw(){
System.out.println("RoundGlyph.draw().radius = " + radius);
}
}
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
}
/*
Glyph() before drwa()
RoundGlyph.draw().radius = 0 // 调用draw() 该方法在子类中被覆盖,此时radius没有被赋初值,默认为0(分配给对象的存储空间初始化成二进制的零)
Glyph() after drwa()
RoundGlyph.RoundGlyph().radius = 5
编写构造器时有一条有效准则,用尽可能简单的方法使对象进入正常状态,如果可以,避免调用其他方法。
*/
8.4 协变返回类型
表示在导出类的被覆盖方法可以返回基类方法的返回类型的某种导出类型
package chapter8polymorphism;
class Grain{
public String toString(){
return "Grain";
}
}
class Wheat extends Grain{
public String toString(){
return "Wheat";
}
}
class Mill{ // 磨坊; 面粉厂;
Grain process(){
return new Grain();
}
}
class WheatMill extends Mill{
Wheat process(){ //"协变返回(covariant return)",仅在subclass(子类)的返回类型是superclass(父类)返回类型的extension(继承)时才被容许。
return new Wheat();
}
}
public class CovariantReturn {
public static void main(String[] args) {
Mill m = new Mill();
Grain g = m.process();
System.out.println(g);
m = new WheatMill();
g = m.process();
System.out.println(g);
}
}
/* Output
Grain
Wheat
*/
8.5 用继承进行设计
package chapter8polymorphism;
// 状态模式 State design pattern
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 { // v. (尤指出乎意料地) 使完全改变
public static void main(String[] args) {
Stage stage = new Stage();
stage.performPlay();
stage.change();
stage.performPlay();
}
}
/* Output
HappyActor
SadActor
*/
8.5.1 纯继承与扩展
纯继承 is-a
扩展
8.5.2 向下转型 与运行时类型识别
package chapter8polymorphism;
// Downcasting & Runtime type information 运行时类型识别 RTTI
// 有向下转型 一定有向上转型
class Useful{
public void f(){}
public void g(){}
}
class MoreUseful extends Useful{
public void f(){}
public void g(){}
public void u(){}
public void v(){}
public void w(){}
}
public class RTTI {
public static void main(String[] args) {
Useful[] x ={
new Useful(),
new MoreUseful(), // 向上转型
};
x[0].f();
x[1].g();
((MoreUseful)x[1]).u(); // 向下转型 运行时类型识别
// ((MoreUseful)x[0]).u(); // ClassCastException
}
}
8.6 总结
不同版本的动态绑定方法