【问题标题】:Guarantee covariant return type with generics in Java用 Java 中的泛型保证协变返回类型
【发布时间】:2015-04-17 00:02:33
【问题描述】:

我有一个名为Point 的类,其方法neighbors() 返回一个Points 数组:

public class Point {
    public Point[] neighbors() { /* implementation not shown */ }
}

我有一个Point 的子类,称为SpecialPoint,它覆盖neighbors() 以返回SpecialPoints 的数组而不是Points。我认为这称为协变返回类型。

public class SpecialPoint extends Point {
    public SpecialPoint[] neighbors() { /* implementation not shown */ }
}

在一个单独的类中,我想将PointSpecialPoint 与泛型一起使用

public <P extends Point> P doStuff(P point) {
    P[] neighbors = point.neighbors();
    // more stuff here including return
}

这不会编译,因为编译器只能保证PPoint 的某个子类,但不能保证Point 的每个子类都会覆盖neighbors() 以返回其自身的数组我碰巧用SpecialPoint完成了,所以Java只知道P#neighbors()返回Point[],而不是P[]

如何保证每个子类都使用协变返回类型覆盖 neighbors(),以便我可以将它与泛型一起使用?

【问题讨论】:

  • P可以是接口吗?

标签: java generics


【解决方案1】:

你可以使用接口:

public interface Point<P extends Point<P>> {
    P[] neighbors();
}

public class SimplePoint implements Point<SimplePoint> {
    @Override
    public SimplePoint[] neighbors() { /* ... */ }
}

public class SpecialPoint implements Point<SpecialPoint> {
    @Override
    public SpecialPoint[] neighbors() { /* ... */ }
}

然后:

public <P extends Point<P>> P doStuff(P point) {
    P[] neighbors = point.neighbors();
    /* ... */
}

如果您仍然需要在实现之间分解代码,那么最好使用抽象类:

public abstract class Point<P extends Point<P>> {
    public abstract P[] neighbors();
    public void commonMethod() { /* ... */ }
}

public class SimplePoint extends Point<SimplePoint> { /* ... */ }

public class SpecialPoint extends Point<SpecialPoint> { /* ... */ }

【讨论】:

  • 哇,我从来没有想过这个。我唯一的问题是,出于其他原因,我仍然希望 SpecialPointSimplePoint 继承。这样它就不会编译,因为Point 中的P 也必须扩展PointP,但SepcialPoint 扩展Point&lt;SimplePoint&gt;。无论如何围绕这个?
  • @JJW5432 还有哪些其他原因?如果目的是分解代码,一个额外的抽象类可以满足您的需求。
  • 是的,大多数其他方法在类之间是相同的,这就是我想要继承的原因。那么就有了AbstractPoint,SimplePoint和SpecialPoint都继承自它并实现Point?
  • @JJW5432 好吧,最好使用抽象类而不是接口,请参阅我的编辑。
  • Point 声明中的绑定对于 OP 的目的来说是未使用且不必要的。 public interface Point&lt;P&gt; 就足够了。
【解决方案2】:

interface Point 可能会解决您的问题:

public class Test  
{

    public interface Point  {
        public Point[] neighbors();
    }

    public class SpecialPoint implements Point {
        public SpecialPoint[] neighbors() { return null; }
    }

    public class SpecialPoint2  implements Point {
        public SpecialPoint2[] neighbors() { return null; }
    }

    public Point doStuff(SpecialPoint point) {
        Point[] neighbors = point.neighbors();
        return neighbors[0];
    }

    public Point doStuff(SpecialPoint2 point) {
        Point[] neighbors = point.neighbors();
        return neighbors[0];
    }
}

【讨论】:

    猜你喜欢
    • 2011-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多