多型與HoFs
朋友們好久不見啊,最近筆者同時在寫指令碼型語言——
JavaScript
,和工業級的面嚮物件語言——Java
。 在寫程式碼的同時呢,也會思考這些語言的不同。今天就拿 Java 中的多型,來談一談吧!
概念
多型(Polymorphism)
多型性的核心是多種表現形式。在 Java
中,多型性是指物件可以擁有多種形式或者說型別。在物件導向的程式設計中,多型與如何將一個物件視為其自身類的例項,或者是它的父類的例項,又或者父類的父類的例項等相關。
上面那段話或許有些抽象,還是讓我們舉個例子吧:
假設我們擁有兩個類:
SLList
類和 VengefulSLList
類,
其中 VengefulSLList
類繼承自 SLList
類。並覆寫(override)了, removeLast
方法(method)。
我們執行以下程式碼:
結果:
sl.addLast(50) ; //VengefullSLList沒有覆寫,呼叫的是父類(即SLList)的方法
sl.removeLast(); //呼叫的是自己覆寫的 removeLast( ) 方法!
再看一個例子:
public static void main(String[] args){
VengefullSLList<Integer> s1 = new VengefullSLList<>(9);
SLList<Integer> s2 = new SLList<>(8);
s1.removeLast(); // 呼叫覆寫的方法
s2.removeLast(); // 呼叫 SLList類的方法
}
事實說明,即使是呼叫同一個方法,根據物件的不同,其產生的結果是多種多樣的!而且,每個物件也能展現不同的型別。
HoF
Higher Order Function: A function that treats another function as data.
高階函式: 是指一個函式把其他函式當成資料。
例如 JavaScript
中的 function
就是一個 物件,可以當做引數傳遞。
在 Python
中我們可以這樣來運用它:
def tenX(x):
return 10*x
def do_twice(f, x):
return f(f(x))
print(do_twice(tenX, 2))
# 200
然而在 Java
中我們沒見過這樣的用法,這是因為在 jdk8 以前 Java
是禁止將函式當引數傳遞的!
問題
那麼問題來了,如果 Java不允許 HoF 的存在,我們怎麼解決這類問題呢?
例如比較大小:
def print_larger(x, y, compare, stringify):
if compare(x, y):
return stringify(x)
return stringify(y)
# HoF 模式
def print_larger(x, y):
if x.largerThan(y):
return x.str()
return y.str()
# Subtype Polymorphism 模式
# 子類的多樣性
我們主要說說第二種方式:
在程式碼中,我們為每個物件提供了 largerThan()
的方法,通過呼叫它實現比大小。但是在 Java
中,如果我們想要實現比較各種型別的物件大小的方法呢?比如說,我們要比較企鵝的大小,我們就要實現 企鵝
類的 largerThan()
方法。我們要比較海豹的大小,就要實現 海豹
類的largerThan()
方法,。。。。。。
我們發現如果直接實現子類的方法,我們無法實現通用的比較方案,在 C++
中我們可以使用過載操作符,在JS
中我們可以傳入 compare
函式。那麼我們在Java
中如何實現呢?
Comparable介面
前面我們提到了多型,有時候我們呼叫同名的方法,也會得到不同的結果。我們可以利用這種特性,來構造一個 compareTo()
方法。
在 Java
中,我們有一個介面(interface) , 叫做 Comparable
。
它規定了所有要實現該介面的類,要實現它的 compareTo(T obj)
方法。
通過介面,我們也可以巧妙的實現,對各種型別的物件,提供一個通用的解決方法!
比如我們要實現一個自己的 Util
類,裡面有一個 max(Comparable[] items )
方法,它的功能是,返回給定的物件陣列中最大的那個物件。
這裡我們使用 Dog
類做演示:
專案目錄:
我們實現了三個類,分別是 Dog
,Util
,Util
程式碼如下:
public class Dog implements Comparable<Dog> {
private int size; // 尺寸
private String name; // 名字
public Dog(){}
public Dog(int size, String name){
this.name = name;
this.size = size;
}
public void bark(){
System.out.println("My name is "+this.name+"!");
}
@Override
public int compareTo(Dog other) { // 覆寫的compareTo()方法
return this.size - other.size;
}
}
public class Util {
public static Comparable max(Comparable[] items){
int maxIndex=0;
// 遍歷找出size最大的狗
for (int i = 0; i < items.length; i++) {
int cmp = items[i].compareTo(items[maxIndex]);
if(cmp>0){
maxIndex = i;
}
}
return items[maxIndex];
}
}
public class LaunchDog {
public static void main(String[] args) {
Dog alice = new Dog(8,"alice");
Dog ben = new Dog(12,"ben");
Dog karn = new Dog(6,"karn");
Dog[] dogs = new Dog[]{alice,ben,karn};
// 呼叫 max() 方法
Dog d =(Dog) Util.max(dogs);
d.bark();
}
}
最後的輸出結果為:
My name is ben!
總結
通過分析以上程式碼,我們發現只要是 實現了 Comparable
介面的類都可以輕鬆使用 Util
類中的 max()
方法選出最大的項。而在 Java
中我們的 集合框架就實現了 Comparable
介面,拿來即用,十分方便。
所以,在專案中我們可以利用 介面(interface) , 來實現 在指令碼語言中用 HoF 實現的功能。這體現了 Java的多型。
總結,Java通過提供介面 賦予了我們使用回撥的能力。
To summarize, interfaces in Java provide us with the ability to make callbacks. Sometimes, a function needs the help of another function that might not have been written yet (e.g.
max
needscompareTo
). A callback function is the helping function (in the scenario,compareTo
).
refer: