package com.company.ch08; public class PrivateOverride { private void func() { System.out.println("private func()"); } public static void main(String[] args) { PrivateOverride privateOverride = new Derived(); privateOverride.func(); } } class Derived extends PrivateOverride { public void func() { // 這裏其實沒有覆蓋。 System.out.println("Derived func()"); } } // private func()
構造器不具備多態性,它們其實是 static 方法,只不過該 static 是隱式聲明的。java
構造器的調用順序:安全
Java 中一般不須要考慮清理的問題,垃圾回收機制會解決大部分問題,可是若是真的須要進行清理操做時,咱們須要手動調用某個特定的函數進行清理操做。由於繼承的緣由,咱們在覆蓋基類的清理函數時,須要調用基類版本的清理函數。一般在導出類清理函數的末尾。同時若是成員對象也有須要清理的話,也須要在清理函數中調用該成員的清理函數。調用的原則就是:清理的順序應該與初始化的順序相同。app
若是某些成員對象存在於其餘一個或多個對象共享的狀況下,咱們不能簡單的調用其清理函數,咱們可使用「引用計數」來跟蹤訪問着共享對象的對象數量(就是C++中的shared_ptr)。dom
若是在一個構造器的內部調用正在構造的對象的某個動態綁定方法,會發生什麼?ide
package com.company.ch08; class Glyph { void draw() { System.out.println("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 r) { radius = r; System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius); } @Override void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); } } public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); } } // Glyph() before draw() // RoundGlyph.draw(), radius = 0 // Glyph() after draw() // RoundGlyph.RoundGlyph(), radius = 5
從上面的輸出能夠看出,在基類中調用動態方法,的確會調用到對應導出類的方法,可是導出類的域卻未完成初始化。函數
初始化實例的過程:this
在構造器內惟一可以安全調用的那些方法是基類中 final 方法(private 方法屬於 final 方法)設計
Java SE5 中添加了協變返回類型,它表示在導出類中的被覆蓋方法能夠返回基類方法的返回類型的某種導出類型。code
package com.company.ch08; 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() { // 關鍵在這裏,本來返回類型應該是 Grain,而這裏使用了 Grain 的導出類 Wheat return new Wheat(); } } public class CovariantReturn { public static void main(String[] args) { Mill mill = new Mill(); Grain grain = mill.process(); System.out.println("grain = " + grain); mill = new WheatMill(); grain = mill.process(); System.out.println("grain = " + grain); } } // grain = Grain // grain = Wheat
咱們應該首先選擇「組合」,尤爲是不能十分肯定應該使用哪一種方法時。組合不會強制咱們的程序誰叫進入繼承的層次結構。並且,組合更加靈活,他能夠動態選擇類型。orm
package com.company.ch08; class Actor { public void act() {} } class HappyActor extends Actor { @Override public void act() { System.out.println("HappyActor"); } } class SadActor extends Actor { @Override 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(); } } // HappyActor // SadActor
咱們經過在運行時將引用與不一樣的對象從新綁定起來,可讓咱們在運行期間得到動態靈活性(也稱爲「狀態模式」)。
繼承表示行爲間的差別,字段表示狀態上的變化。
在 Java 中,全部轉型都會獲得檢查。即便咱們只是進行一次普通的加括弧形式的類型轉換,在進入運行期時仍然會對其進行檢查,若是不是咱們想要轉換的類型,那麼會返回一個 ClassCastException。
package com.company.ch08; public class Cycle { void run() { System.out.println("Cycle run"); } } class Unicycle extends Cycle { @Override void run() { System.out.println("Unicycle run"); } } class Bicycle extends Cycle { @Override void run() { System.out.println("Bicycle run"); } } class Tricycle extends Cycle { @Override void run() { System.out.println("Tricycle run"); } } class Test { static void ride(Cycle c) { c.run(); } public static void main(String[] args) { Unicycle unicycle = new Unicycle(); Bicycle bicycle = new Bicycle(); Tricycle tricycle = new Tricycle(); unicycle.run(); bicycle.run(); tricycle.run(); } } // Unicycle run // Bicycle run // Tricycle run
package com.company.ch08; public class Shape { public void draw() {} public void erase() {} }
package com.company.ch08; public class Circle extends Shape{ @Override public void draw() { System.out.println("Circle draw"); } @Override public void erase() { System.out.println("Circle erase"); } }
package com.company.ch08; public class Square extends Shape{ @Override public void draw() { System.out.println("Square draw"); } @Override public void erase() { System.out.println("Square erase"); } }
package com.company.ch08; public class Triangle extends Shape { @Override public void draw() { System.out.println("Triangle draw"); } @Override public void erase() { System.out.println("Triangle erase"); } }
package com.company.ch08; import java.util.Random; // 工廠模式 public class RandomShapeGenerator { 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 com.company.ch08; public class Shapes { private static RandomShapeGenerator randomShapeGenerator = new RandomShapeGenerator(); public static void main(String[] args) { Shape[] shapes = new Shape[9]; for (int i = 0;i < 9;i++) { shapes[i] = randomShapeGenerator.next(); } for (Shape shape: shapes) { shape.draw(); } } } // Triangle draw // Triangle draw // Square draw // Triangle draw // Square draw // Triangle draw // Square draw // Triangle draw // Circle draw
public class Shape { public void draw() {} public void erase() {} public void info() { System.out.println("Shape info"); } }
即便導出類沒有覆蓋它,可是因爲繼承的緣由,導出類任然會有該方法。
package com.company.ch08; public 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 info() { System.out.println("Circle info"); } }
package com.company.ch08; public class Shapes { private static RandomShapeGenerator randomShapeGenerator = new RandomShapeGenerator(); public static void main(String[] args) { Shape[] shapes = new Shape[9]; for (int i = 0;i < 9;i++) { shapes[i] = randomShapeGenerator.next(); } for (Shape shape: shapes) { shape.info(); } } } // Shape info // Shape info // Circle info // Circle info // Shape info // Shape info // Shape info // Shape info // Circle info
若是隻有一個導出類Circle覆蓋了該方法,只有在正式類型爲Circle的Shape調用info時,纔會調用到覆蓋後的方法,而其他的則是調用到基類的方法。
class Line extends Shape { @Override public void draw() { System.out.println("Line draw"); } @Override public void erase() { System.out.println("Line erase"); } } public class Shapes { private static RandomShapeGenerator randomShapeGenerator = new RandomShapeGenerator(); public static void main(String[] args) { Shape[] shapes = new Shape[9]; for (int i = 0;i < 9;i++) { shapes[i] = randomShapeGenerator.next(); } for (Shape shape: shapes) { shape.draw(); } shapes[0] = new Line(); shapes[0].draw(); } } //Shape info //Shape info //Circle info //Circle info //Shape info //Shape info //Shape info //Shape info //Circle info
package com.company.ch08; public class Cycle { void run() { System.out.println("Cycle run"); } int wheels() { return 0; } } class Unicycle extends Cycle { @Override void run() { System.out.println("Unicycle run"); } @Override int wheels() { return 1; } } class Bicycle extends Cycle { @Override void run() { System.out.println("Bicycle run"); } @Override int wheels() { return 2; } } class Tricycle extends Cycle { @Override void run() { System.out.println("Tricycle run"); } @Override int wheels() { return 3; } } class Test { static void ride(Cycle c) { c.run(); } public static void main(String[] args) { Unicycle unicycle = new Unicycle(); Bicycle bicycle = new Bicycle(); Tricycle tricycle = new Tricycle(); unicycle.run(); bicycle.run(); tricycle.run(); Cycle[] cycles = new Cycle[]{unicycle, bicycle, tricycle}; for (Cycle cycle: cycles) { System.out.println("cycle.wheels() = " + cycle.wheels()); } } } // Unicycle run // Bicycle run // Tricycle run // cycle.wheels() = 1 // cycle.wheels() = 2 // cycle.wheels() = 3
package com.company.ch08; enum Note { MIDDLE_C, C_SHARP, B_FLAT; } class Instrument { void play(Note n) { System.out.println("Instrument.play() n = " + n); } @Override public String toString() { return "Instrument"; } void adjust() { System.out.println("Adusting Instrument"); } } class Wind extends Instrument { @Override void play(Note n) { System.out.println("Wind.play() n = " + n); } } class Percussion extends Instrument { @Override void play(Note n) { System.out.println("Percussion.play() n = " + n); } @Override public String toString() { return "Percussion"; } @Override void adjust() { System.out.println("Adjusting Percussion"); } } class Stringed extends Instrument { @Override void play(Note n) { System.out.println("Stringed.play() n = " + n); } @Override public String toString() { return "Stringed"; } @Override void adjust() { System.out.println("Adjusting Stringed"); } } class Brass extends Wind { @Override void play(Note n) { System.out.println("Brass.play() n = " + n); } @Override void adjust() { System.out.println("Adjusting Brass"); } } class Woodwind extends Wind { @Override void play(Note n) { System.out.println("Woodwind.play() n = " + n); } @Override public String toString() { return "Woodwind"; } } public class Music3 { public static void tune(Instrument i) { i.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 Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind(), }; tuneAll(instruments); for (Instrument instrument: instruments) { System.out.println(instrument); } } } // Wind.play() n = MIDDLE_C // Percussion.play() n = MIDDLE_C // Stringed.play() n = MIDDLE_C // Brass.play() n = MIDDLE_C // Woodwind.play() n = MIDDLE_C // Instrument // Percussion // Stringed // Instrument // Woodwind
class Piano extends Instrument { @Override void play(Note n) { System.out.println("Piano.play() n = " + n); } @Override public String toString() { return "Piano"; } @Override void adjust() { System.out.println("Adjusting Piano"); } } public class Music3 { public static void tune(Instrument i) { i.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 Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind(), new Piano(), }; tuneAll(instruments); for (Instrument instrument: instruments) { System.out.println(instrument); } } } // Wind.play() n = MIDDLE_C // Percussion.play() n = MIDDLE_C // Stringed.play() n = MIDDLE_C // Brass.play() n = MIDDLE_C // Woodwind.play() n = MIDDLE_C // Piano.play() n = MIDDLE_C // Instrument // Percussion // Stringed // Instrument // Woodwind // Piano
class InstrumentGenerator { private Random random = new Random(42); public Instrument next() { switch (random.nextInt(6)) { default: 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(); } } } public class Music3 { public static void tune(Instrument i) { i.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[10]; InstrumentGenerator instrumentGenerator = new InstrumentGenerator(); for (int i = 0;i < 10; i++) { instruments[i] = instrumentGenerator.next(); } tuneAll(instruments); for (Instrument instrument: instruments) { System.out.println(instrument); } } } // Stringed.play() n = MIDDLE_C // Brass.play() n = MIDDLE_C // Wind.play() n = MIDDLE_C // Stringed.play() n = MIDDLE_C // Wind.play() n = MIDDLE_C // Percussion.play() n = MIDDLE_C // Piano.play() n = MIDDLE_C // Stringed.play() n = MIDDLE_C // Percussion.play() n = MIDDLE_C // Piano.play() n = MIDDLE_C // Stringed // Instrument // Instrument // Stringed // Instrument // Percussion // Piano // Stringed // Percussion // Piano
package com.company.ch08; public class Rodent { void eat() { System.out.println("Rodent.eat()"); } public static void main(String[] args) { Rodent[] rodents = new Rodent[] { new Rodent(), new Mouse(), new Gerbil(), new Hamster(), }; for (Rodent rodent: rodents) { rodent.eat(); } } } class Mouse extends Rodent { @Override void eat() { System.out.println("Mouse.eat()"); } } class Gerbil extends Rodent { @Override void eat() { System.out.println("Gerbil.eat()"); } } class Hamster extends Rodent { @Override void eat() { System.out.println("Hamster.eat()"); } } // Rodent.eat() // Mouse.eat() // Gerbil.eat() // Hamster.eat()
package com.company.ch08; class Base { void func1() { func2(); } void func2() { System.out.println("Base"); } } public class Ex10 extends Base { @Override void func2() { System.out.println("Ex10"); } public static void main(String[] args) { Base base = new Ex10(); base.func1(); } } // Ex10
由於func2
既不是static也不是final,因此他是動態綁定的,所以基類的 func1 中調用 func2 方法也是調用到導出類的 func2。
package com.company.ch08; 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"); } } public class Sandwich extends PortableLunch { private Bread b = new Bread(); private Cheese c = new Cheese(); private Lettuce l = new Lettuce(); private Pickle p = new Pickle(); public Sandwich() { System.out.println("Sandwich()"); } public static void main(String[] args) { new Sandwich(); } }
package com.company.ch08; public class Rodent { Rodent() { System.out.println("Rodent"); } void eat() { System.out.println("Rodent.eat()"); } public static void main(String[] args) { Rodent[] rodents = new Rodent[] { new Rodent(), new Mouse(), new Gerbil(), new Hamster(), }; for (Rodent rodent: rodents) { rodent.eat(); } } } class Mouse extends Rodent { Mouse() { System.out.println("Mouse"); } @Override void eat() { System.out.println("Mouse.eat()"); } } class Gerbil extends Rodent { Gerbil() { System.out.println("Gerbil"); } @Override void eat() { System.out.println("Gerbil.eat()"); } } class Hamster extends Rodent { Hamster() { System.out.println("Hamster"); } @Override void eat() { System.out.println("Hamster.eat()"); } }
package com.company.ch08; class Shared { private int refcount = 0; private static long counter = 0; private final long id = counter++; public Shared() { System.out.println("Create " + this); } void addRef() { refcount++; } protected void dispose() { if(--refcount == 0) System.out.println("Disposing " + this); } @Override public String toString() { return "Shared{" + "id=" + id + '}'; } @Override protected void finalize() throws Throwable { System.out.println("finalize()"); if (refcount != 0) { System.out.println("refcount != 0"); } super.finalize(); } } 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(); } @Override public String toString() { return "Composing{" + "id=" + id + '}'; } } 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 composing: composings) { // composing.dispose(); // } new Composing(new Shared()); System.gc(); } }
package com.company.ch08; class Glyph { void draw() { System.out.println("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 r) { radius = r; System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius); } @Override void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); } } class RectangularGlygh extends Glyph { private int length; RectangularGlygh(int length) { this.length = length; System.out.println("RectanguarGlygh length = " + length); } @Override void draw() { System.out.println("RectanguarGlygh.draw() length = " + length); } } public class PolyConstructors { public static void main(String[] args) { new RectangularGlygh(10); } } // Glyph() before draw() // RectanguarGlygh.draw() length = 0 // Glyph() after draw() // RectanguarGlygh length = 10
package com.company.ch08; class Status { void func() {} } class StatusA extends Status { void func() { System.out.println("Status A"); } } class StatusB extends Status { void func() { System.out.println("Status B"); } } class StatusC extends Status { void func() { System.out.println("Status C"); } } class AlterStatus { Status status = new StatusA(); void A() { status = new StatusA(); } void B() { status = new StatusB(); } void C() { status = new StatusC(); } void call() { status.func(); } } public class Starship { public static void main(String[] args) { AlterStatus alterStatus = new AlterStatus(); alterStatus.call(); alterStatus.B(); alterStatus.call(); alterStatus.C(); alterStatus.call(); alterStatus.A(); alterStatus.call(); } } // Status A // Status B // Status C // Status A
package com.company.ch08; public class Cycle { void run() { System.out.println("Cycle run"); } int wheels() { return 0; } } class Unicycle extends Cycle { @Override void run() { System.out.println("Unicycle run"); } @Override int wheels() { return 1; } void balance() {} } class Bicycle extends Cycle { @Override void run() { System.out.println("Bicycle run"); } @Override int wheels() { return 2; } void balance() {} } class Tricycle extends Cycle { @Override void run() { System.out.println("Tricycle run"); } @Override int wheels() { return 3; } } class Test { static void ride(Cycle c) { c.run(); } public static void main(String[] args) { Cycle[] cycles = new Cycle[]{new Unicycle(), new Bicycle(), new Tricycle()}; // for(Cycle cycle: cycles) { // cycle.balance(); // 沒法調用 // } Unicycle unicycle = (Unicycle)cycles[0]; Bicycle bicycle = (Bicycle)cycles[1]; Tricycle tricycle = (Tricycle)cycles[2]; unicycle.balance(); bicycle.balance(); // tricycle.balance(); //沒法調用 } }
本文首發於Code & Fun