java中的多型

Mikejiawei發表於2020-06-07

多型與HoFs

朋友們好久不見啊,最近筆者同時在寫指令碼型語言——JavaScript,和工業級的面嚮物件語言——Java。 在寫程式碼的同時呢,也會思考這些語言的不同。今天就拿 Java 中的多型,來談一談吧!

概念

多型(Polymorphism)

多型性的核心是多種表現形式。在 Java中,多型性是指物件可以擁有多種形式或者說型別。在物件導向的程式設計中,多型與如何將一個物件視為其自身類的例項,或者是它的父類的例項,又或者父類的父類的例項等相關。


上面那段話或許有些抽象,還是讓我們舉個例子吧:

假設我們擁有兩個類:

SLList 類和 VengefulSLList 類,

其中 VengefulSLList 繼承SLList 類。並覆寫(override)了, removeLast 方法(method)

我們執行以下程式碼:

Extends

結果:

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

comparable

它規定了所有要實現該介面的類,要實現它的 compareTo(T obj) 方法。

通過介面,我們也可以巧妙的實現,對各種型別的物件,提供一個通用的解決方法!

比如我們要實現一個自己的 Util類,裡面有一個 max(Comparable[] items )方法,它的功能是,返回給定的物件陣列中最大的那個物件。

這裡我們使用 Dog類做演示:

專案目錄:

我們實現了三個類,分別是 DogUtilUtil

程式碼如下:

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 needs compareTo). A callback function is the helping function (in the scenario, compareTo).


refer:

USB的CS61b

joshhug老師的gitbook

Oracle的文件

相關文章