第8章 多态
练习1:
创建一个Cycle类,它具有子类Unicycle、Bicycle和Tricycle。演示每一个类型的实例都可以经由ride()方法向上转型为Cycle。
代码
package testPackage;
import static testPackage.MyPrint.*;
public class Cycle {
public void run() {
println("Cycle run");
}
public static class Unicycle extends Cycle {
@Override
public void run() {
println("Unicycle run");
}
}
public static class Bicycle extends Cycle {
@Override
public void run() {
println("Bicycle run");
}
}
public static class Tricycle extends Cycle {
@Override
public void run() {
println("Tricycle run");
}
}
public static class PersonGo {
public void ride(Cycle cycle) {
cycle.run();
}
public static void main(String[] args) {
Unicycle unicycle = new Unicycle();
Bicycle bicycle = new Bicycle();
Tricycle tricycle = new Tricycle();
PersonGo personGo = new PersonGo();
personGo.ride(unicycle);
personGo.ride(bicycle);
personGo.ride(tricycle);
}
}
}
输出
Unicycle run
Bicycle run
Tricycle run
练习2:
在几何图形的示例中添加@override注解。
略。编译器的工作。
练习3:
在基类Shapes.java中添加一个新方法,用于打印一条信息,但导出类中不要覆盖这个方法。请解释发生了什么。现在,在其中一个导出类中覆盖该方法,而在其它的导出类中不予覆盖,观察又有发生什么。最后,在所有导出类中覆盖这个方法。
导出类会优先调用覆盖后的方法,其次调用父类方法。
练习4:
向shapes.java中添加一个新的Shape类型,并在main()方法中验证:多态对新类型的作用是否与在旧类型中的一样。
每个导出类和其他导出类父类实现并无区别。
练习5:
以练习1为基础,在Cycle中添加wleels()方法,它将返回轮子的数量。修改ride()方法,让它调用wheels()方法,并验证多态起作用了。
略。导出类覆盖方法返回整形即可。
练习6:
修改Music3.java,使what()方法成为根Object的toString()方法。试用System.out.println打印Instrument对象(不用向上转型)。
testPackage.Cycle$PersonGo@4554617c
打印出包名类名存储地址。
练习7:
向Music3.java添加一个新的类型Instrument,并验证多态性是否作用于所添加的新类型。
骑上我心爱的自行车。
代码
package testPackage;
import java.util.Random;
import static testPackage.MyPrint.*;
public class Cycle {
public void run() {
println("Cycle run");
}
public static class Unicycle extends Cycle {
@Override
public void run() {
println("Unicycle run");
}
}
public static class Bicycle extends Cycle {
@Override
public void run() {
println("Bicycle run");
}
}
public static class Tricycle extends Cycle {
@Override
public void run() {
println("Tricycle run");
}
}
public static class RandomCycles {
private final Random random = new Random(47);
public Cycle next() {
switch (random.nextInt(3)) {
default:
case 0:
return new Bicycle();
case 1:
return new Unicycle();
case 2:
return new Tricycle();
}
}
}
public static class PersonGo {
static RandomCycles randomCycles = new RandomCycles();
public void ride(Cycle cycle) {
cycle.run();
}
public static void main(String[] args) {
Cycle[] cycles = new Cycle[9];
for (int i = 0; i < cycles.length; i++) {
cycles[i] = randomCycles.next();
}
PersonGo personGo = new PersonGo();
for (Cycle cycle : cycles) {
personGo.ride(cycle);
}
}
}
}
输出
Tricycle run
Tricycle run
Unicycle run
Tricycle run
Unicycle run
Tricycle run
Unicycle run
Tricycle run
Bicycle run
练习9:
创建Rodent(啮齿动物): Mouse(老鼠),Gerbil(鼹鼠),Hamster (大颊鼠)等等的这样一个层次结构。在基类中,提供所有的Rondent都通用的方法,在导出类中,根据特定的Rodent类型覆盖这些方法,以便他们执行不同的行为。创建一个Robent数组,填充不同的Rodent,然后调用基类方法,观察发生什么情况。
就像上面一样。
练习10:
创建一个包含两个方法的基类。在第一个方法中可以调用第二个方法。然后产生一个继承自该基类的导出类,且覆盖基类中的第二个方法。为该导出类创建一个对象,将他向上转型到基类类型并调用第一个方法,解释发生的情况。
代码
package testPackage;
import java.util.Random;
import static testPackage.MyPrint.*;
public class Cycle {
public void run() {
println("Cycle run");
println(toString());
}
@Override
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public static class Unicycle extends Cycle {
@Override
public void run() {
println("Unicycle run");
println(toString());
}
@Override
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
}
public static class Bicycle extends Cycle {
@Override
public void run() {
println("Bicycle run");
println(toString());
}
@Override
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
}
public static class Tricycle extends Cycle {
@Override
public void run() {
println("Tricycle run");
println(toString());
}
@Override
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
}
public static class RandomCycles {
private final Random random = new Random(47);
public Cycle next() {
switch (random.nextInt(3)) {
default:
case 0:
return new Bicycle();
case 1:
return new Unicycle();
case 2:
return new Tricycle();
}
}
}
public static class PersonGo {
static RandomCycles randomCycles = new RandomCycles();
public void ride(Cycle cycle) {
cycle.run();
}
public static void main(String[] args) {
Cycle[] cycles = new Cycle[9];
for (int i = 0; i < cycles.length; i++) {
cycles[i] = randomCycles.next();
}
PersonGo personGo = new PersonGo();
for (Cycle cycle : cycles) {
personGo.ride(cycle);
}
}
}
}
输出
Tricycle run
testPackage.CycleTricycle@74a14482TricycleruntestPackage.CycleTricycle@74a14482 Tricycle run testPackage.CycleTricycle@74a14482TricycleruntestPackage.CycleTricycle@1540e19d
Unicycle run
testPackage.CycleUnicycle@677327b6TricycleruntestPackage.CycleUnicycle@677327b6 Tricycle run testPackage.CycleUnicycle@677327b6TricycleruntestPackage.CycleTricycle@14ae5a5
Unicycle run
testPackage.CycleUnicycle@7f31245aTricycleruntestPackage.CycleUnicycle@7f31245a Tricycle run testPackage.CycleUnicycle@7f31245aTricycleruntestPackage.CycleTricycle@6d6f6e28
Unicycle run
testPackage.CycleUnicycle@135fbaa4TricycleruntestPackage.CycleUnicycle@135fbaa4 Tricycle run testPackage.CycleUnicycle@135fbaa4TricycleruntestPackage.CycleTricycle@45ee12a7
Bicycle run
testPackage.Cycle$Bicycle@330bedb4
在子类中,父类的方法被覆盖了。
练习11:
向Sandwich中添加Pickle类。
略。
练习12:
修改练习9,使其能够演示基类和导出类的初始化顺序。然后向基类和导出类添加成员对象,并说明构建期间初始化发生的顺序。
略。先基类,后导出类,先声明时初始化的成员对象后构造器中初始化的成员对象。
练习13:
在ReferenceCounting.java中添加一个finalize()方法,用来校验终止条件(查看第5章)。
代码
package referencePackage;
import static testPackage.MyPrint.*;
public class Composing {
private Shared shared;
private static long counter = 0;
private final long id = counter++;
public Composing(Shared shared) {
println("Creating " + this);
this.shared = shared;
this.shared.addRef();
}
protected void dispose() {
println("disposing " + this);
shared.dispose();
}
@Override
public String toString() {
return "Composing " + id;
}
@Override
protected void finalize() throws Throwable {
if (shared.getRef() == 0) {
println("finalized now");
super.finalize();
} else {
println("is still quoted");
}
}
}
package referencePackage;
import static testPackage.MyPrint.*;
public class Shared {
private int refCount = 0;
private static long counter = 0;
private final long id = counter++;
public Shared() {
println("Creating " + this);
}
public void addRef() {
refCount++;
}
public int getRef() {
return refCount;
}
protected void dispose() {
if (--refCount == 0) {
println("Disposing " + this);
}
}
@Override
public String toString() {
return "Shared" + id;
}
@Override
protected void finalize() throws Throwable {
if (refCount == 0) {
println("finalized now");
super.finalize();
} else {
println("is still quoted");
}
}
}
package referencePackage;
import static testPackage.MyPrint.*;
public class ReferenceCounting {
public static void main(String[] args) {
Shared shared = new Shared();
Composing[] composings = {new Composing(shared), new Composing(shared), new Composing(shared),
new Composing(shared), new Composing(shared)};
for (Composing c : composings) {
c.dispose();
}
System.gc();
}
}
输出
Creating Shared0
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 Shared0
练习14:
修改练习12,使得某个成员变为具有引用计数的共享对象,并证明它可以正确运行。
代码
package rodent;
import static testPackage.MyPrint.*;
public class Rodent {
public Rodent(TotalNum totalNum){
totalNum.addTotal();
}
public void predation() {
println("Rodent eat.");
}
}
package rodent;
import static testPackage.MyPrint.*;
public class Mouse extends Rodent{
public Mouse(TotalNum totalNum) {
super(totalNum);
}
@Override
public void predation() {
println("Mouse eat");
}
}
package rodent;
import static testPackage.MyPrint.*;
public class Hamster extends Rodent {
public Hamster(TotalNum totalNum) {
super(totalNum);
}
@Override
public void predation() {
println("Hamster eat.");
}
}
package rodent;
import static testPackage.MyPrint.*;
public class Gerbil extends Rodent {
public Gerbil(TotalNum totalNum) {
super(totalNum);
}
@Override
public void predation() {
println("Gerbil eat.");
}
}
输出
Mouse eat
Gerbil eat.
Hamster eat.
3
练习15:
在PolyConstructor.java中添加一个RectangularGlyph,并证明会出现本节所描述的问题。
代码
package draw;
import static testPackage.MyPrint.*;
public class Glyph {
public Glyph() {
println("Glyph 1");
draw();
println("Glyph 2");
}
public void draw() {
println("Glyph draw");
}
public static class RectangleGlyph extends Glyph {
public RectangleGlyph() {
}
@Override
public void draw() {
println("RectangleGlyph draw");
}
}
public static class PolyConstructor {
public static void main(String[] args) {
new RectangleGlyph();
}
}
}
输出
Glyph 1
RectangleGlyph draw
Glyph 2
练习16:
遵循Transmogrify.java这个例子,创建一个Starship类,包含一个AlerSatus引用,此引用可以指示三种不同的装了。纳入一些可以改变这些状态的方法。
代码
package draw;
import sun.management.Sensor;
import static testPackage.MyPrint.*;
public class Do16 {
public static void main(String[] args) {
StarShip starShip = new StarShip(new Status());
starShip.status.alert();
for (int i = 0; i < 3; i++) {
starShip.changeStatus(i);
starShip.status.alert();
}
}
public static class StarShip {
private Status status = new Status();
public StarShip(Status status) {
this.status = status;
}
public Status getStatus() {
return status;
}
public void changeStatus(int i) {
switch (i) {
default:
status = new Status();
case 1:
status = new FirstStatus();
case 2:
status = new SecondStatus();
case 3:
status = new ThirdStatus();
}
}
}
public static class Status {
public void alert() {
println("status alert");
}
}
public static class FirstStatus extends Status {
@Override
public void alert() {
println("First alert");
}
}
public static class SecondStatus extends Status {
@Override
public void alert() {
println("Second alert");
}
}
public static class ThirdStatus extends Status {
@Override
public void alert() {
println("Third alert");
}
}
}
输出
status alert
Third alert
Third alert
Third alert
练习17:
使用练习1中的Cycle的层次结构,在Unicycle和Bicycle中添加balance()方法,而Tricycle中不添加。创建所有这三种类型的实例,并将他们向上转型为Cycle数组。在该数组的每一个元素上都尝试调用balance(),并观察结果。然后将他们向上转型,再次调用balance(),并观察所产生什么。
略。向上转型编译报错,向下转型有该方法可以调用,没有不可调用。
本文通过一系列练习探讨了多态性的概念及其应用。包括创建不同类型的Cycle子类,并演示如何通过父类引用调用子类方法;添加新方法并观察多态行为;创建Rodent类层次结构来展示多态性等。
655

被折叠的 条评论
为什么被折叠?



