1. 动态绑定
又称"后期绑定"或"运行时绑定",它的含义就是在运行时判断对象的类型,从而调用恰当的方法
public class Shapes { private static RandomShapeGenerator gen = new RandomShapeGenerator(); public static void main(String[] args) { Shape[] shapeArr = new Shape[9]; // 填充数组 for (int i = 0; i < shapeArr.length; i++){ shapeArr[i] = gen.next(); } // 动态调用方法 for (Shape shape : shapeArr){ shape.draw(); } } } class RandomShapeGenerator { private Random rand = new Random(47); public Shape next() { switch (rand.nextInt(3)) { default: case 0: return new Circle(); case 1: return new Square(); case 2: return new Triangle(); } } } class Shape { public void draw() { System.out.println("Shape.draw()"); } public void erase() { System.out.println("Shape.erase()"); } } class Circle extends Shape { public void draw() { System.out.println("Circle.draw()"); } public void erase() { System.out.println("Circle.erase()"); } } class Triangle extends Shape { public void draw() { System.out.println("Triangle.draw()"); } public void erase() { System.out.println("Triangle.erase()"); } } class Square extends Shape { public void draw() { System.out.println("Square.draw()"); } public void erase() { System.out.println("Square.erase()"); } } /* Output: Triangle.draw() Triangle.draw() Square.draw() Triangle.draw() Square.draw() Triangle.draw() Square.draw() Triangle.draw() Circle.draw() *///:~
2. "覆盖"私有方法:
我们期望的输出是public f(),但是由于private方法被自动认为是final方法,而且对子类是屏蔽的,因此在这种情况下,
Derived类中的f()方法就是一个全新的方法;
结论:只有非private方法才可以被覆盖,所以在子类中,对于父类中的private方法,最好采用不同的名字。
public class PrivateOverride { private void f() { print("private f()"); } public static void main(String[] args) { PrivateOverride po = new Derived(); po.f(); } } class Derived extends PrivateOverride { public void f() { print("public f()"); } } /* Output: private f() *///:~
3. 构造器和多态:
复杂对象调用构造器要遵循下面的顺序:
1) 调用父类构造器(如有多层,则会不断递归下去)
2) 按声明顺序调用成员的初始化方法
3) 调用子类构造器的主体
class Meal { Meal() { print("Meal()"); } } class Bread { Bread() { print("Bread()"); } } class Cheese { Cheese() { print("Cheese()"); } } class Lettuce { Lettuce() { print("Lettuce()"); } } class Lunch extends Meal { Lunch() { print("Lunch()"); } } class PortableLunch extends Lunch { PortableLunch() { print("PortableLunch()"); } } public class Sandwich extends PortableLunch { private Bread bread = new Bread(); private Cheese cheese = new Cheese(); private Lettuce lettuce = new Lettuce(); public Sandwich() { print("Sandwich()"); } public static void main(String[] args) { new Sandwich(); } } /* Output: Meal() Lunch() PortableLunch() Bread() Cheese() Lettuce() Sandwich()
4. 编写构造器时,应尽可能简单地使对象进入正常状态,如果可以的话,避免调用其它方法。
下面的例子我们会发现radius的值为0,为什么?
一个动态绑定的方法调用会深入到继承层次结构内部,它可以调用子类的方法,然而此时方法所操纵的成员还没有进行初始化。
class Glyph { void draw() { print("Glyph.draw()"); } Glyph() { print("Glyph() before draw()"); this.draw(); print("Glyph() after draw()"); } } class RoundGlyph extends Glyph { private int radius = 1; RoundGlyph(int r) { radius = r; print("RoundGlyph.RoundGlyph(), radius = " + radius); } void draw() { print("RoundGlyph.draw(), radius = " + radius); } } public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); } } /* Output: Glyph() before draw() RoundGlyph.draw(), radius = 0 Glyph() after draw() RoundGlyph.RoundGlyph(), radius = 5 *///:~
之所以调用的是子类的draw方法,this的含义是谁调用我,this指向的就是谁,Glyph构造器是通过RoundGlyph类构造器中super()方法触发,所以this指向的是RoundGlyph中的draw方法
5. "向上转型"与"向下转型"
向上转型:List list = new ArrayList(); list.add("xxx") 此时调用的其实是ArrayList的方法
注意:向上转型之后,无法访问子类中的新加的方法
向下转型:其实就是强转,前提是我们知道它是某一种类型,否则运行时会报ClassCastException
时间: 2024-10-12 10:16:19