类在通用接口中实现自身是一种好习惯吗?

Dav*_*Rlz 6 java generics

对问题标题表示道歉,我无法轻易将其写入文字.

我在一些代码中遇到过这个问题:

public class MyClass implements Message<MyClass> {...}
Run Code Online (Sandbox Code Playgroud)

我理解它的作用,但我以前从未见过以这种方式宣布的类.

我看到的缺点是现在MyClass是一个消息,需要包含与其主要目的无关的已实现方法.

我看到的一个优点(除了它减少了我本来需要编写的其他类的数量)是因为对于类似的事情Comparable,MyClass会知道如何将自己与其他实例进行比较,这反过来会使代码更简洁.

这是好习惯吗?有没有经验法则?

Lou*_*man 5

这或多或少是Java中唯一一种具有引用实现类本身的方法的接口的方法.因此,例如,您可以编写二叉树节点接口:

interface TreeNode<N extends TreeNode<N>> {
  N getLeftChild();
  N getRightChild();
  void setLeftChild(N node);
  void setRightChild(N node);
}
Run Code Online (Sandbox Code Playgroud)

然后你有类似的课程

class TreeNodeWithInt extends TreeNode<TreeNodeWithInt> {
  int value;
  TreeNodeWithInt leftChild;
  TreeNodeWithInt rightChild;
  public TreeNodeWithInt getLeftChild() { return leftChild; }
  public void setLeftChild(TreeNodeWithInt newLeft) { leftChild = newLeft; }
  ...
}
Run Code Online (Sandbox Code Playgroud)

如果我们没有Ntype参数,你将被迫编写不安全的代码

class TreeNodeWithInt extends TreeNode {
  int value;
  TreeNodeWithInt leftChild;
  TreeNodeWithInt rightChild;

  public void setLeftChild(TreeNode node) {
    // note the dangerous cast!
    leftChild = (TreeNodeWithInt) node;
  }
}
Run Code Online (Sandbox Code Playgroud)

这里的关键问题是,当接口描述输入和返回类型的方法时,不允许接口引用实现接口的类的类型.因此,您需要包含"自我"泛型类型参数.这是代码中相对常见的习惯用法,它广泛使用泛型.

正如您所正确识别的那样,它经常被Comparable特别使用,因为您应该只能将对象与相同类型的其他对象进行比较.实际上,Collections.sort指定采用List<T>where T extends Comparable<? super T>,这意味着至少T可以与其他类型的值相比,但也可能是其他值.T

(最后,正如你所料 - 因为它是实现这种行为的唯一方法,它不是"好"或"坏"的实践.也就是说,该技术的目标是避免编写没有警告而编译但可以结束的方法投掷ClassCastException,这本身就是一种很好的做法.)