Overview
看到书中的例子我以为我都懂了,不过看到了一个例子之后,才发现我都是半懂,没有仔细思考,看书的时候心不静。关于多态有一个优先级可以概括,详见http://blog.youkuaiyun.com/thinkghoster/archive/2008/04/19/2307001.aspx。优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
Example and research
class A {
public String show(D obj){
return ("A and D");
}
public String show(A obj){
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{}
class D extends B{}
以下是结果
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b)); ①
System.out.println(a1.show(c)); ②
System.out.println(a1.show(d)); ③
System.out.println(a2.show(b)); ④
System.out.println(a2.show(c)); ⑤
System.out.println(a2.show(d)); ⑥
System.out.println(b.show(b)); ⑦
System.out.println(b.show(c)); ⑧
System.out.println(b.show(d)); ⑨
其中4,5,6,9全部做错。那就一个一个验证这个优先级吧。
System.out.println(a2.show(b))
之前看过书中有这样的例子:
import java.util.*;
class Shape {
void draw() {System.out.println("Shape.draw()");}
void erase() {}
}
class Circle extends Shape {
void draw() {
System.out.println("Circle.draw()");
}
void erase() {
System.out.println("Circle.erase()");
}
}
class Square extends Shape {
void draw() {
System.out.println("Square.draw()");
}
void erase() {
System.out.println("Square.erase()");
}
}
class Triangle extends Shape {
void draw() {
System.out.println("Triangle.draw()");
}
void erase() {
System.out.println("Triangle.erase()");
}
}
// A "factory" that randomly creates shapes:
class RandomShapeGenerator {
private Random rand = new Random();
public Shape next() {
switch(rand.nextInt(3)) {
default:
case 0: return new Circle();
case 1: return new Square();
case 2: return new Triangle();
}
}
}
public class Shapes {
private static RandomShapeGenerator gen =
new RandomShapeGenerator();
public static void main(String[] args) {
Shape[] s = new Shape[9];
// Fill up the array with shapes:
for(int i = 0; i < s.length; i++)
s[i] = gen.next();
// Make polymorphic method calls:
for(int i = 0; i < s.length; i++){
s[i].draw();
};
}
}
结果如下:
Square.draw()
Circle.draw()
Triangle.draw()
Triangle.draw()
Triangle.draw()
Circle.draw()
Square.draw()
Triangle.draw()
Circle.draw()
每一个父类Shape引用的都是子类,输出的也都是子类的方法。所以我以为对于4中应该输出"B AND B"。但是注意到调用的方法在父类中一个在父类中定义过了,一个没有。什么意思?如果在类A中加上这么一段:
public String show(B obj){
return ("A and BB");
}
那么4的结果就是"B AND B"。这是类A和B中都有一个同样的方法show(B obj)。那为什么4的结果是"B AND A"了?注意到刚才说的优先级,首先查找this.show(),这是是没有对应的方法的。接着查找super.show(),super.show是没有的,因为a2的定义是A a2 = new B(),a2还是一个类型为a的引用变量。接着查找this.show((super)O),这样就找到了对应的方法了,为类A中的show(A object)方法,但是注意子类B中有方法把他给覆盖了!所以使用的类B中的方法!结果为"B and A"。
其他的都同理可以论证了。
My thinking in java
加上了多态后,立刻变的复杂了。从面向过程转到面向对象我还非常不习惯,习惯于参数必须和声明的参数类型完全一样。有了多态和抽象类到底有什么好处,为什么要引入这两个东西了?
-
抽象类
我觉得抽象类主要是提高代码的可读性,如果没有抽象类也一样可以实现这样的功能。比如在父类中的方法实现就写为空,然后在子类中覆盖就行了,加上了abstract之后只不过加上了语法的检查。
-
多态和继承
多态是一个利器,不过很有可能让代码变的更糟糕。父类和子类有三种情况:
-
父类方法比子类多
这种情况下公共的接口最好用abstract,父类中多出来的方法,作为所有子类的公共方法使用设置为Public让子类继承。
-
父类方法和子类一样多
这个时候最好父类的方法都用来继承,提供公共的接口。
-
父类方法少于子类
相同的部分作为公共接口,子类中多出来的方法可以用downcasting。
这样定义类时都可以用父类的引用使用子类方法。