【问题标题】:Method chaining + inheritance 2 or more times方法链 + 继承 2 次或更多次
【发布时间】:2015-06-10 17:58:33
【问题描述】:

我无法将构建在彼此之上的多个向量类链接起来。我希望能够扩展该类。

这是二维的:

public class Vec2 < C extends Vec2 > {

    public double x, y;

    public Vec2() {
    }

    public Vec2(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public C add(double x, double y) {
        this.x += x;
        this.y += y;
        return (C) this;
    }

}

这是一个带有 z 元素的向量。

class Vec3 < C extends Vec3 > extends Vec2<Vec3> {

    double z;

    public Vec3(){}

    public Vec3(double x, double y, double z) {
        super(x, y);
        this.z = z;
    }

    public C add(double x, double y, double z) {
        super.add(x, y);
        this.z  += z;
        return (C) this;
    }
}

但是什么时候使用 Vec3,那么只要我连续两次使用 Vec2 中的方法,它就会返回 Vec2。

 Vec3<Vec3> a = new Vec3<>();
 // ------------------------------------------------->.add() in Vec2 cannot be aplied
 a.add(10, 20).add(10, 20, 10).add(10, 20).add(10, 20).add(10, 10, 20);

我不想这样写课程:

class Vec3 extends Vec2<Vec3> {

    // constructor etc. like before...

    public Vec3 add(double x, double y, double z) {
        super.add(x, y);
        this.z  += z;
        return this;
    }
}

因为当我制作 Vec4 时,我必须覆盖 Vec3 中的每个方法。

有没有办法(语法)解决这个问题?无论如何它都会返回正确的类。

【问题讨论】:

  • This,不过不知道能降多少级。
  • 我认为你不能走得太远,而这个 无论在哪里它总是返回正确的类,如果没有开发人员的参与几乎是不可能的。

标签: java inheritance chaining


【解决方案1】:

问题是您的定义中有很多“原始”类型,例如

Vec2 < C extends Vec2 >
                 ----
                 raw type!

几轮之后,你会得到一个原始类型,erasure 使CVec2 相同。


我们可以做以下事情,使用类型变量This作为“自我类型”

public class Vec2<This> {

    public This add(double x, double y) {
        this.x += x;
        this.y += y;
        return (This) this;
    }

}

public class Vec3<This> extends Vec2<This> {

    public This add(double x, double y, double z) {
        super.add(x, y);
        this.z  += z;
        return (This) this;
    }
}

public class Vec4<This> extends Vec3<This> {

etc.

但是等一下,我们如何将This 提供给Vec3

    Vec3<Vec3<Vec3<......>>>    ???

我们可以使用辅助类

public class V3 extends Vec3<V3>{}

现在一切正常; V3 中的所有 add() 方法都返回 V3

    V3 a = new V3();
    a.add(10, 20).add(10, 20, 10).add(10, 20).add(10, 20).add(10, 10, 20);

【讨论】:

  • @clankill3r - 好吧,你不能反驳
  • 您基本上是对的,只是这不是您指定 自引用 类型的方式。改用这个:Vec2 &lt; C extends Vec2 &lt;C&gt;&gt; 并保留 OP 的代码原样(即返回 C
  • @Bohemian - 这是流行的做法,但我反对。界限是复杂的,令人困惑的,并且类主体无论如何都不需要/使用。并且调用站点不能真正使用绑定来强制C 是“自我类型”。见stackoverflow.com/questions/30382847/…
  • 因此我建议我们简单地采用一个约定俗成的名称This来表示这种类型变量;忘记界限。
【解决方案2】:

您无法完全按照您的预期实现您的代码,但以下编译并且我相信您的意图:

interface Vec<C extends Vec<C>> {
    C add(C c);
}

class Vec2 implements Vec<Vec2> {
    public double x, y;
    public Vec2() {
    }

    public Vec2(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public Vec2 add(Vec2 c) {
        this.x += c.x;
        this.y += c.y;
        return this;
    }
}

static class Vec3 implements Vec<Vec3> {
    Vec2 vec2;
    double z;
    public Vec3() {
        this(0,0,0);
    }

    public Vec3(double x, double y, double z) {
        vec2 = new Vec2(x, y);
        this.z = z;
    }

    public Vec3 add(Vec3 c) {
        vec2.add(new Vec2(c.vec2.x, c.vec2.y));
        this.z  += z;
        return this;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    相关资源
    最近更新 更多