package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 5:54 PM */ public class PrivateOverride { private void f(){ System.out.println("private f()"); } public static void main(String[] args) { PrivateOverride privateOverride = new Derived(); privateOverride.f(); } } class Derived extends PrivateOverride{ public void f(){ System.out.println("public f()"); } }
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 5:57 PM */ public class FieldAccess { public static void main(String[] args) { /** * Upcast */ Super sup = new Sub(); System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField()); Sub sub = new Sub(); System.out.println("sup.field = " + sub.field + ", sup.getField() = " + sub.getField() + ", sum.getSuperField() = " + sub.getSuperField()); } } class Super { public int field = 0; public int getField() { return field; } } class Sub extends Super { public int field = 1; @Override public int getField() { return field; } public int getSuperField() { return super.field; } }
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 6:07 PM */ public class StaticPolymorphism { public static void main(String[] args) { /** * Upcast */ StaticSuper sup = new StaticSub(); System.out.println(sup.staticGet()); System.out.println(sup.dynamicGet()); } } 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()"; } @Override public String dynamicGet() { return "Derived dynamicGet()"; } }
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 6:18 PM */ public class Sandwich extends PortableLunch { private Bread bread = new Bread(); private Cheese cheese = new Cheese(); private Lettuce lettuce = new Lettuce(); public Sandwich() { System.out.println("Sandwich()"); } public static void main(String[] args) { new Sandwich(); } } 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()"); } }
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 7:14 PM */ public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); } } class Glyph { void draw() { System.out.println("Sup-Glyph.draw()"); } Glyph() { System.out.println("Glyph() before draw()"); draw(); System.out.println("Glyph() after draw()"); } } class RoundGlyph extends Glyph { private int radius = 1; RoundGlyph(int radius) { this.radius = radius; System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius); } @Override void draw() { System.out.println("Sub-RoundGlyph.draw(), radius = " + radius); } }
初始化的实际过程:
1)在其他任何事物发生之前,将分配给对象的存储空间初始化为二进制的0;
2)如前所述那样调用基类构造器。此时,调用被覆盖后的draw()方法(要在调用RoundGlyph构造器之前调用),由于步骤1的缘故,此时radius为0;
3)按照声明的顺序调用成员的初始化方法;
4)调用导出类的构造主体。
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 7:29 PM */ public class CovariantReturn { public static void main(String[] args) { Mill mill = new Mill(); Grain grain = new Grain(); System.out.println(grain); mill = new WheatMill(); grain = mill.process(); System.out.println(grain); } } class Grain{ @Override public String toString() { return "Grain"; } } class Wheat extends Grain{ @Override public String toString() { return "Wheat"; } } class Mill{ Grain process() { return new Grain(); } } class WheatMill extends Mill{ @Override Wheat process() { return new Wheat(); } }
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 7:43 PM */ public class RTTI { public static void main(String[] args) { Useful[] usefuls = { new Useful(), new MoreUseful() }; usefuls[0].f(); usefuls[1].g(); /** * Downcast/RTTI */ ((MoreUseful)usefuls[1]).u(); /** * Exception thrown */ ((MoreUseful)usefuls[0]).u(); } } class Useful { public void f() { } public void g() { } } class MoreUseful extends Useful { @Override public void f() { } @Override public void g() { } public void u() { } public void v() { } public void w() { } }
练习1: 创建一个Circle类,它具有子类Unicycle、Bicycle和Tricycle。演示每一个类型的实例都可以经由ride()方法向上转型至Cycle。
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 7:59 PM */ public class Biking { public static void ride(Cycle cycle) { cycle.travel("" + cycle); } public static void main(String[] args) { Unicycle unicycle = new Unicycle(); Bicycle bicycle = new Bicycle(); Tricycle tricycle = new Tricycle(); ride(unicycle); ride(bicycle); ride(tricycle); } } class Cycle { public void travel(String s) { System.out.println("Cycle.travel " + s); } } class Unicycle extends Cycle { @Override public String toString() { return "Unicycle"; } } class Bicycle extends Cycle { @Override public String toString() { return "Bicycle"; } } class Tricycle extends Cycle { @Override public String toString() { return "Tricycle"; } }
练习2: 在几何图形的示例中添加@Override注解。
package thinkinginjava.charpenter8; import java.util.Random; /** * @author Spring-_-Bear * @version 2021/09/28 7:44 PM */ public class Shapes { private static RandomShapeGenerator generator = new RandomShapeGenerator(); public static void main(String[] args) { Shape[] shapes = new Shape[9]; /** * Fill up the array with Shape references */ for (int i = 0; i < shapes.length; i++) { shapes[i] = generator.next(); } for (Shape shp : shapes) { shp.draw(); } } } 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()"); } } class RandomShapeGenerator { private Random random = new Random(55); public Shape next() { switch (random.nextInt(3)) { case 0: return new Circle(); case 1: return new Square(); case 2: return new Triangle(); default: } return null; } }
练习3: 在基类Shape.java中添加一个新方法,用于打印一条消息,但导出类中不要覆盖这个方法。请解释发生了什么。现在,在其中一个导出类中覆盖该方法,而在其它导出类中不要覆盖,观察又发生了什么。最后,在所有的导出类中覆盖这个方法。
package thinkinginjava.charpenter8; import java.util.Random; /** * @author Spring-_-Bear * @version 2021/09/28 7:44 PM */ public class Shapes { private static RandomShapeGenerator generator = new RandomShapeGenerator(); public static void main(String[] args) { Shape[] shapes = new Shape[9]; /** * Fill up the array with Shape references */ for (int i = 0; i < shapes.length; i++) { shapes[i] = generator.next(); } for (Shape shp : shapes) { shp.draw(); shp.erase(); shp.amend(); } } } class Shape { public void draw() { System.out.println("Shape.draw()"); } public void erase() { System.out.println("Shape.amend()"); } public void amend() { System.out.println("Shape.amend()"); } } class Circle extends Shape { @Override public void draw() { System.out.println("Circle.draw()"); } @Override public void erase() { System.out.println("Circle.erase()"); } @Override public void amend() { System.out.println("Circle.amend()"); } } class Square extends Shape { @Override public void draw() { System.out.println("Square.draw()"); } @Override public void erase() { System.out.println("Square.erase()"); } @Override public void amend() { System.out.println("Square.amend()"); } } class Triangle extends Shape { @Override public void draw() { System.out.println("Triangle.draw()"); } @Override public void erase() { System.out.println("Triangle.erase()"); } @Override public void amend() { System.out.println("Triangle.amend()"); } } class RandomShapeGenerator { private Random random = new Random(55); public Shape next() { switch (random.nextInt(3)) { case 0: return new Circle(); case 1: return new Square(); case 2: return new Triangle(); default: } return null; } }
练习4: 向Shapes.java中添加一个新的Shape类型,并在main()方法中验证:多态对新类型的作用是否与在旧类型中的一样。
package thinkinginjava.charpenter8; import java.util.Random; /** * @author Spring-_-Bear * @version 2021/09/28 7:44 PM */ public class Shapes { private static RandomShapeGenerator generator = new RandomShapeGenerator(); public static void main(String[] args) { Shape[] shapes = new Shape[9]; /** * Fill up the array with Shape references */ for (int i = 0; i < shapes.length; i++) { shapes[i] = generator.next(); } for (Shape shp : shapes) { shp.draw(); shp.erase(); shp.amend(); } } } class Shape { public void draw() { System.out.println("Shape.draw()"); } public void erase() { System.out.println("Shape.amend()"); } public void amend() { System.out.println("Shape.amend()"); } } class Circle extends Shape { @Override public void draw() { System.out.println("Circle.draw()"); } @Override public void erase() { System.out.println("Circle.erase()"); } @Override public void amend() { System.out.println("Circle.amend()"); } } class Square extends Shape { @Override public void draw() { System.out.println("Square.draw()"); } @Override public void erase() { System.out.println("Square.erase()"); } @Override public void amend() { System.out.println("Square.amend()"); } } class Triangle extends Shape { @Override public void draw() { System.out.println("Triangle.draw()"); } @Override public void erase() { System.out.println("Triangle.erase()"); } @Override public void amend() { System.out.println("Triangle.amend()"); } } class RandomShapeGenerator { private Random random = new Random(55); public Shape next() { switch (random.nextInt(4)) { case 0: return new Circle(); case 1: return new Square(); case 2: return new Triangle(); case 3: return new Oval(); default: } return null; } } class Oval extends Shape { @Override public void draw() { System.out.println("Oval.draw()"); } @Override public void erase() { System.out.println("Oval.erase()"); } @Override public void amend() { System.out.println("Oval.amend()"); } }
练习5: 以练习1为基础,在Cycle中添加wheels()方法,它将返回轮子的数量。修改ride()方法,让它调用wheels()方法,并验证多态起作用了。
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 7:59 PM */ public class Biking { public static void ride(Cycle cycle) { cycle.travel("" + cycle); cycle.wheels(); } public static void main(String[] args) { Unicycle unicycle = new Unicycle(); Bicycle bicycle = new Bicycle(); Tricycle tricycle = new Tricycle(); ride(unicycle); ride(bicycle); ride(tricycle); } } class Cycle { private int wheels = 4; public void travel(String s) { System.out.println("Cycle.travel " + s); } public void wheels() { System.out.println("Cycle.wheels = " + wheels); } } class Unicycle extends Cycle { private int wheels = 1; @Override public String toString() { return "Unicycle"; } @Override public void wheels() { System.out.println("Unicycle.wheels = " + wheels); } } class Bicycle extends Cycle { private int wheels = 2; @Override public String toString() { return "Bicycle"; } @Override public void wheels() { System.out.println("Bicycle.wheels = " + wheels); } } class Tricycle extends Cycle { private int wheels = 3; @Override public String toString() { return "Tricycle"; } @Override public void wheels() { System.out.println("Tricycle.wheels = " + wheels); } }
练习6: 修改Music3.java,使what()方法成为根Object的toString()方法。使用System.out.println()方法打印Instrument对象(不用向上转型)。
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 2021/09/28 8:04 PM */ public class Music3 { public static void tune(Instrument instrument) { instrument.play(Note.MIDDLE_C); } public static void tuneAll(Instrument[] instruments) { for (Instrument instrument : instruments) { tune(instrument); } } public static void main(String[] args) { /** * Upcasting during addition to the array. */ Instrument[] instruments = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind() }; tuneAll(instruments); } } enum Note { MIDDLE_C, C_SHARP, B_FLAT; } class Instrument{ void play(Note note) { System.out.println("Instrument.play() " + note); } @Override public String toString() { return "Instrument"; } void adjust(){ System.out.println("Adjusting Instrument"); } } class Wind extends Instrument{ @Override void play(Note note){ System.out.println("Wind.play() " + note); } @Override public String toString() { return "Wind"; } @Override void adjust() { System.out.println("Adjusting Wind"); } } class Percussion extends Instrument{ @Override void play(Note note) { System.out.println("Percussion.play() " + note); } @Override public String toString() { return super.toString(); } @Override void adjust() { System.out.println("Adjusting Percussion"); } } class Stringed extends Instrument{ @Override void play(Note note) { System.out.println("Stringed.play() " + note); } @Override void adjust() { System.out.println("Adjusting Stringed"); } @Override public String toString() { return "Stringed"; } } class Brass extends Wind{ @Override void play(Note note) { System.out.println("Brass.play() " + note); } @Override void adjust() { System.out.println("Adjusting Brass"); } } class Woodwind extends Wind{ @Override void play(Note note){ System.out.println("Woodwind.play() " + note); } @Override public String toString() { return "Woodwind"; } }
练习7: 向Music.java添加一个新的类型Instrument,并验证多态性是否作用于所添加的新类型。
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 2021/09/28 8:04 PM */ public class Music3 { public static void tune(Instrument instrument) { instrument.play(Note.MIDDLE_C); } public static void tuneAll(Instrument[] instruments) { for (Instrument instrument : instruments) { tune(instrument); } } public static void main(String[] args) { /** * Upcasting during addition to the array. */ Instrument[] instruments = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind(), new Piano() }; tuneAll(instruments); } } enum Note { MIDDLE_C, C_SHARP, B_FLAT; } class Instrument { void play(Note note) { System.out.println("Instrument.play() " + note); } @Override public String toString() { return "Instrument"; } void adjust() { System.out.println("Adjusting Instrument"); } } class Wind extends Instrument { @Override void play(Note note) { System.out.println("Wind.play() " + note); } @Override public String toString() { return "Wind"; } @Override void adjust() { System.out.println("Adjusting Wind"); } } class Percussion extends Instrument { @Override void play(Note note) { System.out.println("Percussion.play() " + note); } @Override public String toString() { return super.toString(); } @Override void adjust() { System.out.println("Adjusting Percussion"); } } class Stringed extends Instrument { @Override void play(Note note) { System.out.println("Stringed.play() " + note); } @Override void adjust() { System.out.println("Adjusting Stringed"); } @Override public String toString() { return "Stringed"; } } class Brass extends Wind { @Override void play(Note note) { System.out.println("Brass.play() " + note); } @Override void adjust() { System.out.println("Adjusting Brass"); } } class Woodwind extends Wind { @Override void play(Note note) { System.out.println("Woodwind.play() " + note); } @Override public String toString() { return "Woodwind"; } } class Piano extends Instrument { @Override void play(Note note) { System.out.println("Piano.play() " + note); } }
练习8: 修改Music3.java,使其可以像Shapes.java中的方式那样随机创建Instrument的对象。
package thinkinginjava.charpenter8; import java.util.Random; /** * @author Spring-_-Bear * @version 2021/09/28 8:04 PM */ public class Music3 { public static void tune(Instrument instrument) { instrument.play(Note.MIDDLE_C); } public static void tuneAll(Instrument[] instruments) { for (Instrument instrument : instruments) { tune(instrument); } } public static void main(String[] args) { Instrument[] instruments = new Instrument[6]; RandomInstrumentGenerator randomInstrumentGenerator = new RandomInstrumentGenerator(); for (int i = 0; i < instruments.length; i++) { instruments[i] = randomInstrumentGenerator.next(); } tuneAll(instruments); } } enum Note { MIDDLE_C, C_SHARP, B_FLAT; } class Instrument { void play(Note note) { System.out.println("Instrument.play() " + note); } @Override public String toString() { return "Instrument"; } void adjust() { System.out.println("Adjusting Instrument"); } } class Wind extends Instrument { @Override void play(Note note) { System.out.println("Wind.play() " + note); } @Override public String toString() { return "Wind"; } @Override void adjust() { System.out.println("Adjusting Wind"); } } class Percussion extends Instrument { @Override void play(Note note) { System.out.println("Percussion.play() " + note); } @Override public String toString() { return super.toString(); } @Override void adjust() { System.out.println("Adjusting Percussion"); } } class Stringed extends Instrument { @Override void play(Note note) { System.out.println("Stringed.play() " + note); } @Override void adjust() { System.out.println("Adjusting Stringed"); } @Override public String toString() { return "Stringed"; } } class Brass extends Wind { @Override void play(Note note) { System.out.println("Brass.play() " + note); } @Override void adjust() { System.out.println("Adjusting Brass"); } } class Woodwind extends Wind { @Override void play(Note note) { System.out.println("Woodwind.play() " + note); } @Override public String toString() { return "Woodwind"; } } class Piano extends Instrument { @Override void play(Note note) { System.out.println("Piano.play() " + note); } } class RandomInstrumentGenerator { private Random random = new Random(47); public Instrument next() { switch (random.nextInt(6)) { case 0: return new Wind(); case 1: return new Percussion(); case 2: return new Stringed(); case 3: return new Brass(); case 4: return new Woodwind(); case 5: return new Piano(); default: } return null; } }
练习9: 创建Rode(啮齿动物):Mouse(老鼠),Gerbil(鼹鼠),Hamster(大颊鼠),等等这样一个继承层次结构。在基类中,提供对所有的Rodent都通用的方法,在导出类中,根据特定的Rodent类型覆盖这些方法,以便它们执行不同的行为。创建一个Robent数组,填充不同的Rodent类型,然后调用基类方法,观察发生什么情况。
package thinkinginjava.charpenter8; import java.util.Random; /** * @author Spring-_-Bear * @version 2021/9/30 23:07 */ public class RodentTester { private static RandomRodentGenerator generator = new RandomRodentGenerator(); public static void main(String[] args) { Rodent[] rodents = new Rodent[10]; for (Rodent rodent : rodents) { rodent = generator.next(); System.out.println(rodent + ": "); rodent.eat(); rodent.run(); } } } class Rodent { protected void eat() { System.out.println("Rodent.eat()"); } protected void run() { System.out.println("Rodent.run()"); } @Override public String toString() { return "Rodent"; } } class Mouse extends Rodent { @Override protected void eat() { System.out.println("Mouse.eat()"); } @Override protected void run() { System.out.println("Mouse.run()"); } @Override public String toString() { return "Mouse"; } } class Gerbil extends Rodent { @Override protected void run() { System.out.println("Gerbil.run()"); } @Override protected void eat() { System.out.println("Gerbil.eat()"); } @Override public String toString() { return "Gerbil"; } } class RandomRodentGenerator { private Random random = new Random(55); public Rodent next() { switch (random.nextInt(2)) { case 0: return new Mouse(); case 1: return new Gerbil(); default: } return null; } }
练习10: 创建一个包含两个方法的基类。在第一个方法中可以调用第二个方法。然后产生一个继承自该基类的导出类,且覆盖基建类中的第二个方法。为该导出类创建一个对象,将它向上转型到基类型并调用第一个方法,解释发生的情况。
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 2021/10/1 14:55 */ public class PolyMethod extends SuperMethod { @Override protected void method2() { System.out.println("PolyMethod.method()"); } public static void main(String[] args) { /** * Upcasting */ SuperMethod polyMethod = new PolyMethod(); polyMethod.method1(); } } class SuperMethod{ protected void method1(){ System.out.println("SuperMethod.method1()"); method2(); } protected void method2() { System.out.println("SuperMethod.method2()"); } }
练习11: 向Sandwich.java中添加Pickle类。
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 9/29/21 6:18 PM */ public class Sandwich extends PortableLunch { private Bread bread = new Bread(); private Cheese cheese = new Cheese(); private Lettuce lettuce = new Lettuce(); private Pickle pickle = new Pickle(); public Sandwich() { System.out.println("Sandwich()"); } public static void main(String[] args) { new Sandwich(); } } 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()"); } } class Pickle { Pickle() { System.out.println("Pickle()"); } }
练习12: 修改练习9,使其能够演示基类和导出类的初始化顺序。然后向基类和导出类中添加成员对象,并说明构架期间初始化发生的顺序。
package thinkinginjava.charpenter8; /** * @author Spring-_-Bear * @version 2021/9/30 23:07 */ public class RodentTester { public static void main(String[] args) { Rodent mouse = new Mouse(); System.out.println(mouse + ": "); mouse.eat(); mouse.run(); mouse.sleep(); } } class Characteristic { private String s; Characteristic(String s) { this.s = s; System.out.println("Creating Characteristic " + s); } } class Description { private String s; Description(String s) { this.s = s; System.out.println("Creating Description " + s); } } class Rodent { private String name = "Rodent"; private Characteristic c = new Characteristic("has tail"); private Description d = new Description("small mammal"); Rodent() { System.out.println("Rodent()"); } protected void eat() { System.out.println("Rodent.eat()"); } protected void run() { System.out.println("Rodent.run()"); } protected void sleep() { System.out.println("Rodent.sleep()"); } @Override public String toString() { return name; } } class Mouse extends Rodent { private String name = "Mouse"; private Characteristic c = new Characteristic("likes cheese"); private Description d = new Description("nocturnal"); Mouse() { System.out.println("Mouse()"); } @Override protected void eat() { System.out.println("Mouse.eat()"); } @Override protected void run() { System.out.println("Mouse.run()"); } @Override protected void sleep() { System.out.println("Mouse.sleep()"); } @Override public String toString() { return name; } }
练习13: 在ReferenceCounting.java中添加一个finalize()方法,用来校验中终止条件(查看第5章)。
练习14: 修改练习12,使得其某个成员对象变为具有引用计数的共享对象,并验证它可以正确运行。
练习15: 在PolyConstructors.java中添加一个RectangleGlyph,并验证会出现本节所描述的问题。
练习16: 遵循Transmogrify.java这个例子,创建一个Starship类,包含一个AlertStatus引用,此引用可以指示三种不同的状态。纳入一些可以改变这些状态的方法。
练习17: 使用练习1中的Cycle的层次结构,在Unicycle和Bicycle中添加balance()方法,而Tricycle不用添加。创建所有这三种类型的实例,并将它们向上转型为Cycle数组。在该数组的每一个元素上都尝试调用balance(),并观察结果。然后将它们向下转型,再次调用balance(),并观察将产生什么。