我正在阅读Naftalin的《Java泛型和集合》一书.我想判断一下我对他们在第三章中提出的一点的理解.

他们解释了Comparable接口如何允许我们控制我们可以相互比较的类型.在下面他们提供的代码示例中,他们说不可能比较AppleOrange.确切地说,他们是这么说的:

由于苹果实现了Comparable<Apple>,很明显,你可以将苹果与苹果进行比较,但不能与橙子进行比较.

但正如您所看到的,在main方法的最后一行,我们可以这样做,因为基类中的compareTo最终被调用.所以我认为解决这个问题的方法是复制compareTo方法的实现,将其移动到AppleOrange类中的每一个?把它从基础Fruit类中移除?还是有更好的方法?

abstract class Fruit {
    protected String name;
    protected int size;

  protected Fruit(String name, int size) {
    this.name = checkNotNull(name);
    this.size = size;
  }

  @Override
  public boolean equals(Object o) {
    if (o instanceof Fruit) {
      Fruit that = (Fruit) o;
      return this.name.equals(that.name) && this.size == that.size;
    }
    return false;
  }

  @Override
  public int hashCode() {
    return name.hashCode() * 29 + size;
  }

  protected int compareTo(@Nullable Fruit that) {
    if (this.size > that.size) {
      return 1;
    } else if (this.size < that.size) {
      return -1;
    } else return 0;
  }
  }
}

class Apple extends Fruit implements Comparable<Apple> {
  public Apple(int size) {
    super("Apple", size);
  }

  @Override
  public int compareTo(Apple apple) {
    return super.compareTo(apple);
  }
}

class Orange extends Fruit implements Comparable<Orange> {
  protected Orange(int size) {
    super("Orange", size);
  }

  @Override
  public int compareTo(Orange orange) {
    return super.compareTo(orange);
  }
}

class TestFruit {
  public static void main(String[] args) {
    Apple apple1 = new Apple(1);
    Apple apple2 = new Apple(2);
    Orange orange1 = new Orange(1);
    Orange orange2 = new Orange(2);

    List<Apple> apples = List.of(apple1, apple2);
    List<Orange> oranges = List.of(orange1, orange2);

    // Both of these work as expected
    System.out.println(Collections.max(apples)); // Apple{name=Apple, size=2}
    System.out.println(Collections.max(oranges)); // Orange{name=Orange, size=2}

    // But now, as expected, when you try to create a mixed list, it will no longer work
    List<Fruit> mixed = List.of(apple1, orange2);
    // Compile error on the below line
    System.out.println(Collections.max(mixed));

    // But this also works now, because compareTo from the Fruit class
    // is being used here.
    System.out.println(apple1.compareTo(orange1)); // -1
  }
}

推荐答案

  1. 一个类有方法compareTo(Fruit)并不意味着它实现了Comparable<Fruit>.只有相反的说法是正确的.
  2. 在JavaAPI中,需要比较的方法基于Comparable接口,而不是判断类是否有compareTo方法.

由于Fruit没有实现Comparable<Fruit>(如果它实现了,这是一个设计问题),这本书所说的是正确的.你可以看到Collections.max不能用List<Fruit>来称呼.

IMO, what make us confuse is the method name compareTo in Fruit.

  • The name is ambiguous to Comparable method,
    So by convention, we should name a method compareTo only when we implements Comparable.
  • 由于静态绑定,可能会调用错误的方法

虽然它被标记为protected(这避免了其他包类的使用),但如果我们将其重命名为其他类,则非常清楚.

Java相关问答推荐

如何粘合(合并)文件Lucene?

使用java访问具体子类特定方法的最佳方法是什么?

在bash中将数组作为Java程序的参数传递

AssertJ Java:多条件断言

使SLF4J在Android中登录到Logcat,在测试中登录到控制台(Gradle依赖问题)

SpringBoot:在条件{Variable}.isBlank/{Variable}.isEmpty不起作用的情况下进行路径变量验证

在macOS上读取文件会导致FileNotFound,即使文件存在(并且具有权限)

在线程Java中调用Interrupt()之后调用Join()

Java Flux中的延迟增加

如何使用jooq更新记录?

如何在Spring Security中设置一个任何人都可以打开的主页?

如何在Spring Boot中为不同的部署环境管理多个.properties文件?

没有Google Play服务,Firebase Auth无法工作

在JSON上获取反斜杠

JAVA 正则表达式识别字符串string或字符串内的字符char

为什么方法接受协变类型的匿名泛型类对象?

为什么 Rust 原生库在调用函数时会随机崩溃?

没有 Stream API 的 Collection GroupBy 聚合

如何在 BlueJ 中自动关闭控制台

Quarkus uber-jar 未与 primefaces 一起运行