【问题标题】:Can I provide methods that use generic types where the generic type is always the class?我可以提供使用泛型类型始终是类的泛型类型的方法吗?
【发布时间】:2011-06-07 22:00:35
【问题描述】:

我不确定我是否很好地传达了这个问题,并且我找不到更好的方法来做到这一点,因为我对 java 还是很陌生。

如果我有课,我相信最好的方式是举例说明

public abstract class Genome
{
    abstract public Genome randomize();
    abstract public Genome mutate();
    abstract public Genome crossOver(Genome genome);
}

我能否确保它的子类总是使用泛型实现

public class GenomeSubclass extends Genome
{
    public GenomeSubclass randomize();
    // etc...
}

而不是合约中提供的抽象方法?

【问题讨论】:

  • 您的帖子中没有显示任何通用代码。您显示的内容称为“协变返回”,其中子类方法覆盖可以返回被覆盖方法返回类型的子类。不知道你在问什么。
  • 他希望方法具有与当前扩展抽象类的类相同的返回类型。嗯,我想这就是他想要的。
  • 致命:谢谢我的意思。
  • Jim:我没有展示,因为这正是我要寻找的答案。

标签: java generics subclassing


【解决方案1】:

通常的方法是这样定义它:

public abstract class Genome<T extends Genome<T>> {
    abstract public T randomize();
    abstract public T mutate();
    abstract public T crossOver(T genome);
}

public class GenomeSubclass extends Genome<GenomeSubclass>
{
    public GenomeSubclass randomize();
    // etc...
}

这也是 Comparable(或至少 Comparable 的大多数用途)和 Enum 使用的方法。

当然,这并不能避免继承其他子类。


编辑以详细说明我的评论:

你不能两者兼得

class GenomeSubclass extends Genome {
    public GenomeSubclass crossOver(GenomeSubclass other);
}

class GenomeSubSubclass extends GenomeSubclass {
    public GenomeSubclass crossOver(GenomeSubSubclass other);
}

虽然两者都在实施相同的基因组方法。 GenomeSubSubclass 的每个子类型都必须实现crossOver(GenomeSubclass) 方法,并且不能进一步限制参数。

当然,您可以为GenomeSubclass 提供自己的类型参数:

public class GenomeSubclass<T extends GenomeSubclass<T>> extends Genome<GenomeSubclass<T>>
{
    public GenomeSubclass<T> randomize();
    // etc...
}

但是如果不以某种方式返回原始类型,您就不能真正直接使用这个类。 (你必须写GenomeSubclass&lt;GenomeSubclass&lt;GenomeSubclass&lt;...&gt;&gt;&gt;,这实际上是不可能的。或者我在这里想错了。)


这里的主要思想是每个被用作类型参数的基因组子类型T 都将兼容它自己的所有子类型。这意味着,我们可以这样:

public abstract class GenomeA extends Genome<GenomeA> {}

然后

public class AImpl1 extends GenomeA {
   public GenomeA randomize();
   public GenomeA mutate();
   public GenomeA crossOver(GenomeA other);
}

public class AImpl2 extends GenomeA {
   public GenomeA randomize();
   public GenomeA mutate();
   public GenomeA crossOver(GenomeA other);
}

【讨论】:

  • 这也意味着所有不同的派生类都没有共同的基类。
  • 这样做不允许 GenomeSubclass 的派生类拥有自己的方法。
【解决方案2】:

不幸的是,Java 没有 This 类型,与 this 对象相反。

通过通用技巧模拟This是可以的,但是太讨厌了。我宁愿永远不要这样做。

现在,你为什么需要它?唯一已知的用法是方法链接。如果您有不同的用例,请告诉我,那将非常有趣。

如果只是为了方法链,我个人认为缺少This没什么大不了的。

编辑crossover(This) 是一个有趣的主题。

假设我们有超类G,以及子类AB。假设A只能crossover(A),而B只能和Bcrossover 操作是G 上的常用操作吗?

不在我们的类型系统中。当然,我们可以认为这两个crossover() 相关,但这种关系无法在我们的类型系统中表达。不能强制要求 X 必须声明方法 crossover(X)。 (泛型也不能强制执行;想想X extends G&lt;Y&gt;

这里有必要去“非语言”,使用另一种语言(英语)和另一种编译器(我们的眼球)来表达和加强这种关系。或者,发明一种新的静态分析器,配备能够表达这种关系的语法。可能需要运行时反射来执行不寻常的方法分派。

大概是这样的:

/** verbal contract: subclass X must declare method `X crossover(X)` **/
class G

    // no explicit crossover() declaration in G

    static <X extends G> X crossover(X x1, X x2)
        X1 = x1.getClass(), X2 = x2.getClass();
        check: X2 is assignable to X1
        check: X1 has method `X1 crossover(X1)`
        invoke dynamic x1.crossover(x2)

class A

    A crossover(A)

【讨论】:

  • 我认为基因组的例子已经很不错了——你想要(例如)一个 DNAGenome 和一个 RNAGenome 类,它们每个都可以被突变以创建新的,并与其他的交叉同种,但不与其他类型的。
  • 当涉及到这类事情时,我实际上并不知道 Java 范式是什么。例如,基因组的一个派生类的实例可以与同一个派生类的一个实例交叉,而交叉通常需要了解从派生类调用的方法。
  • @Paŭlo @Adam crossover 确实突破了极限。在编辑中查看我的理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-25
  • 2021-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多