Lec 10 - Subtype Polymorphism vs. HoFs
这一章真的很绕。
Dynamic Method Selection Puzzle
首先看这样一个问题。答案是除了最后一个o3.bark()会报错,其他都调用的ShowDog()的bark()。后者是因为dynamic type均为ShowDog,前者需要仔细说一下。
上回书说道:如Object o3 = (Dog) o2;
这种形式的casting,不改变compile-time type。这里这个不改变,是对等号两端均无改变(compile-time type的定义中就说了它永远不会变)。所以,o3的compile-time type仍为Object,dynamic type为ShowDog。当call bark() method时,发现Object中并无此方法,故报错 (Compiler allows calls based on static type)。
static方法不能Override(还没想明白为什么)
Subtype Polymorphism vs. Explicit HoFs
Polymorphism: providing a single interface to entities of different types
如上图,deque的compile-time type是deque,不管他的run-time type是什么,比如LinkedDeque或者ArrayDeque,deque.addFirst()都会根据当前run-time type,实现相同的功能。这就是Polymorphism。
Application 1: Comparables
DIY OurComparable
Josh想建一个对任何array都适用的max()方法,发现不好整。如上图,运行到if (items[i] > items[maxDex])
这里会出错,因为两个Object怎么比大小呢?比的应该是Dod的size才对,这咋整呢?
对任何都适用,是不是想到了以前学过的interface inheraitance?
- Step 1,建立一个interface
public interface OurComparable {
/** Return nagtive if this < o
* Return 0 if this = o
* Return positive if this > o
*/
public int compareTo(Object o);
}
需要有一个方法compareTo,实现比较类大小的功能。
Object o也可变为OurComparable o,因为只有继承OurComparable的类才能进行比较。
- Step 2, 让Dog继承,并编写compareTo方法具体实现
public class Dog implements OurComparable {
private String name;
private int size;
public Dog(String n, int s) {
name = n;
size = s;
}
public void bark() {
System.out.println(name + " says: bark");
}
/** Return negative if this dog is less than the dog pointed at by o...*/
public int compareTo(Object o) {
Dog uddaDog = (Dog) o; //Casting
return this.size - uddaDog.size;
}
- Step 3, 在max()方法中改变形参、返回值以及compareTo
public class Maximizer {
public static OurComparable max(OurComparable[] items) {
int maxDex = 0;
for (int i = 0; i < items.length; i += 1) {
int cmp = items[i].compareTo(items[maxDex]);
if (cmp > 0) {
maxDex = i;
}
}
return items[maxDex];
}
}
和之前步骤一样。思想是:max方法中发现类无法比大小,于是就要建立一个对所有类都适用的比大小方法compareTo,因此要建立interface。比上一个例子难想,因为数据类型的方法,addFirst(), addLast()这种都已经建立好了,而且都是相同的,只要想到建立interface就结束了。这里还要想到建立compareTo方法。
目前是不是看起来像是绕了个大圈?直接在Dog里建个dogMax方法不好么,反正还得建interface,Dog里还得建compareTo的具体实现。似乎代码上一点没省。
Comparables of Java
OurComparable存在一些问题。首先,comparaTo的实现中需要进行Dog uddaDog = (Dog) obj;
这一步的casting,不好看而且不安全,小问题。重点是,目前除了Dog,没有其它的class继承了OurComparable,所以显得这个操作这么多余。
聪明的Java早就想到了! 他早就建好了名为Comparable的interface,各种libraries里都使用了Comparable!各种类都继承了Comparable!
public class Dog implements Comparable<Dog>
这么继承,免去了casting的烦恼。再把OurCoparable改为Comparable,完成。
还记得String.compareTo
这个方法么?String就继承了Comparable,所以,现在的max方法对String也适用!完成了polymorphism!
有很多个库,它们建立的时候就使用了Comparable(可以把Maximizer看作一个库)。综上,如果我们在自己的类里继承了Comparable,就意味着这些库中的方法(比如Arrays.sort, Arrays.asList, Collection.sort)可以应用在我们的类上!如果我们建立的库应用了Comparable,那么所有继承Comparable的类都可以应用我们建立的库中的方法!太激动了
PS.
public class Dog implements Comparable<Dog>
此为继承Comparable
public class Maximizer {
public static Comparable max(Comparable[] items) {}
}
此为应用Comparable。
Application 2: Comparators
如果想要实现按照Dog.name排序呢?那是不是还要建一个Dog.compareByName方法?肯定不行,没有实现polymorphism,这不是又回到解放前了么。
如图,在explicit HoF方式下,很容易实现不同的compare方法,比如String类型或者int类型,换一种compare输入就行。然而在subtype方式下也就是Java中,是如图所示的形式,一会举一个代表方法——Collection.sort()的例子。
- 首先在Dog类中建立NameComparator类,继承Comparator类,具体实现其compare(T a, T b)方法。其中String类型的name比较就用的之前提到的compareTo方法
Comparator中有很多方法,但是只有compara必须重写。
private static class NameComparator implements Comparator<Dog> {
public int compare(Dog a, Dog b){
return a.name.compareTo(b.name);
}
}
/** 因为NameComparator是private */
public static Comparator<Dog> getNameComparator() {
return new NameComparator();
}
compare方法重写不难,但是为什么要加一个getNameComparator呢?因为把NameComparator设置成private了,那为什么设置成private呢?
- 调用
如果NameComparator是Dog中的一个public类,那么,调用方式是这样的:
Dog.NameComparator = new Dog.NameComparator;
而java一般不是这么干的。通过以上操作,实现了这种调用方式:
Comparator<Dog> nc = Dog.getNameComparator();
Comparator可以容纳Dog.NameComparator类因为他们是继承关系,所以此处可以这么初始化,贴合了java的默认方式,目前尚不明白这样有什么好处。
import java.util.Comparator;
public class DogLauncher {
public static void main(String[] args) {
Dog[] dogs = {new Dog("Elyse", 3), new Dog("Sture", 9),
new Dog("Benjamin", 15)};
System.out.println(Maximizer.max(dogs));
maxDog.bark();
Comparator<Dog> nc = Dog.getNameComparator();
if (nc.compare(dogs[0], dogs[2]) > 0) { // if d1 comes later than d3 in the alphabet
dogs[0].bark();
} else {
dogs[3].bark();
}
}
}
Josh用了最后一小节讲Comparator。前面的Comparable听的还行,这里我直接晕掉了。个人感觉这里应该给些示例要不总有种绕了半天圈子功能还是那样的感觉。
目前看是看懂了,但是自己实现还是需要一定的练习。本章学的头都大了,快乐数据结构就到此为止了么?