CS61B-4.3关于多态的理解

4.3是博主在做proj1的时候遇到的一个不熟练的知识点,重点关于多态,包含了Java中高级函数的实现,以及泛型,接口,继承等概念的使用.

多态的引入

假设我们想编写一个 python 程序,用于打印两个对象中较大的对象的字符串表示形式。有两种方法可以做到这一点。

  1. 显式高阶函数方法
def print_larger(x, y, compare, stringify):
    if compare(x, y):
        return stringify(x)
    return stringify(y)
  1. 子类多态方法
def print_larger(x, y):
    if x.largerThan(y):
        return x.str()
    return y.str()

使用显式高阶函数方法,我可以打印出2个数中较大的那个,但是使用子类多态方法是对象本身做出选择

实现OurComparable

重点实现了一个优雅的MAX方法

Say we want to write a max function which takes in any array - regardless of type - and returns the maximum item in the array.

首先来看个错误的案例:

public static Object max(Object[] items) {
    int maxDex = 0;
    for (int i = 0; i < items.length; i += 1) {
        if (items[i] > items[maxDex]) {
            maxDex = i;
        }
    }
    return items[maxDex];
}

public static void main(String[] args) {
    Dog[] dogs = {new Dog("Elyse", 3), new Dog("Sture", 9), new Dog("Benjamin", 15)};
    Dog maxDog = (Dog) max(dogs);
    maxDog.bark();
}

上面代码有一个编译错误,那就是在if (items[i] > items[maxDex])这个语句的时候,>不能直接比较两个Object对象.

我们可以创建一个接口来保证任何实现类都包含一个比较方法,我们称之为compareTo
Pasted image 20240420013651.png

编写接口并指定方法 :

public interface OurComparable {
    public int compareTo(Object o);
}

我们可以这样定义判断规则:

  • if this > o return -1
  • if this = o return 0
  • if this > o return 1

接下来,我们就要让Dog类来实现接口了

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");
    }

    public int compareTo(Object o) {
        Dog uddaDog = (Dog) o;
        if (this.size < uddaDog.size) {
            return -1;
        } else if (this.size == uddaDog.size) {
            return 0;
        }
        return 1;
    }
}```

现在,我们就可以将`Max`方法推广为可以接受任何`OurComparable`对象的方法了

```Java
public class Max {
	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的类型是OurComparable呢,这玩意不是一个接口吗?
在上面我们的Dog类实现了OurComparable,所以Dog相当于OurComparable的子类,这里OurComparable[]接受的其实是我们传过去的Dog[]
Pasted image 20240420091004.png

这里提出一个思考,那么没有实现OurComparable的类,还能使用max方法吗?
答案是当然不能的,所以我们将要引入Java内建的Comparable,后面就会讲到

其实可以修改compareTo的规则来让代码更加简洁:

  • Return negative number if this < o.
    如果 this < o,则返回负数。
  • Return 0 if this equals o.
    如果 this 等于 o,则返回 0。
  • Return positive number if this > o.
    如果 this > o,则返回正数。

代码示例:

public int compareTo(Object o) {
   Dog uddaDog = (Dog) o;
   return this.size - uddaDog.size;
}

Java内建的Comparable

但是这样仍然不完美

  1. 比如已经存在的类,如String,他就没有实现OurComparable,难道我们还要重写String?那显然是不现实的,那我们该怎么办?
  2. comparaTo实现中需要进行Dog uddaDog = (Dog) obj;这种强制类型转换(casting),不好看且不安全

解决方案是直接使用Comparable

Pasted image 20240420015644.png

采用了泛型,这样就避免了将对象转换为特定的类型

public class Dog implements Comparable<Dog> {
    ...
    public int compareTo(Dog uddaDog) {
        return this.size - uddaDog.size;
    }
}

Comparator和自定义比较方法

但是思考一下,假如我们想按照别的规则来比较大小该如何实现呢,比如按照名字首字母顺序?

接下来我们定义一个概念:

自然顺序(Natural order)用于指代特定类 compareTo 的方法中隐含的顺序
Natural order - used to refer to the ordering implied in the compareTo method of a particular class.

在上面的例子中,自然顺序就是狗的size大小

Java的解决办法是使用Comparator接口

public interface Comparator<T> {
    int compare(T o1, T o2);
}

这表明接口 Comparator 要求任何实现类都实现该 compare 方法。(嵌套实现)compare的规则 就像: compareTo

  • Return negative number if o1 < o2.
    如果 o1 < o2,则返回负数。
  • Return 0 if o1 equals o2.
    如果 o1 等于 o2,则返回 0。
  • Return positive number if o1 > o2.
    如果 o1 > o2,则返回正数。

让我们给Dog类添加一个NameComparator!
请注意,我们已将 NameComparator 声明为静态类
privateNameComparator再public一个getNameComparator

import java.util.Comparator;

public class Dog implements Comparable<Dog> {
   ...
   public int compareTo(Dog uddaDog) {
       return this.size - uddaDog.size;
   }

   private static class NameComparator implements Comparator<Dog> {
       public int compare(Dog a, Dog b) {
           return a.name.compareTo(b.name);
       }
   }

   public static Comparator<Dog> getNameComparator() {
       return new NameComparator();
   }
}

注意!NameComparator中的return a.name.compareTo(b.name);语句中的compareToString类的compareTo,并不是我们在上面Dog类中重写的

注意是按照字符串首字母在字母表中的顺序进行比较,而不是字符串大小

好了,现在我们再来看一下继承关系图

Pasted image 20240420110311.png

工作原理: Comparator是内建于Java的,我们可以在Dog类中定义我们自己的比较方法(NameComparator,SizeComparator等)

总结

总结一下Comparator需要在我们自己的比较方法中实现compare方法

比如

private static class NameComparator implements Comparator<Dog> {
        public int compare(Dog a, Dog b) {
            ...
        }
    }

Comparable要求在实现类中实现compareTo方法
对于Dog类来说,我们定义这个compareTo方法是按照size来比较

这应该就是所谓的特定类的compareTo方法的自然顺序

Pasted image 20240420111952.png

这里给出GPT3.5的解释:
在Java中,实现Comparable接口并重写compareTo方法的类通常被称为具有"自然顺序"(natural ordering)或者"内在顺序"(intrinsic ordering)。这是因为compareTo方法定义了该类对象之间的默认比较规则,即这种比较规则是对象本身固有的,而不是外部传入的比较器所定义的。
因此,你在Dog类中重写的compareTo方法可以被称为该类的"自然顺序"或"内在顺序"比较方法,因为它定义了两个Dog对象之间在特定属性(这里是size)上的默认比较规则。

例如

public class Dog implements Comparable<Dog> {
    ...
    public int compareTo(Dog uddaDog) {
        return this.size - uddaDog.size;
    }
}

但是我再次强调一下,虽然上面已经说过一次

public int compareTo(Dog uddaDog) {
        return this.size - uddaDog.size;
    }

    private static class NameComparator implements Comparator<Dog> {
        public int compare(Dog a, Dog b) {
            return a.name.compareTo(b.name);
        }
    }

NameComparator中的compareTo是String类的重写方法,并不是我们刚刚在Dog类中的重写的!这一点不正体现了Java的多态性吗?这就是我对多态的初步认识

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇