首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >创建具有泛型方法的不可变基

创建具有泛型方法的不可变基
EN

Stack Overflow用户
提问于 2014-02-10 04:58:00
回答 2查看 131关注 0票数 2

我有一个基类:

代码语言:javascript
复制
public abstract class BasePiece extends Serialisable {
    public final Position[] shape;
    public final Position position;

    public abstract Position[] getInitialShape();

    public BasePiece() {
        position = new Position(0, 0);
        shape = getInitialShape();
    }
    public BasePiece(Position pos, Position[] initialShape) {
        position = pos;
        shape = initialShape;
    }

    public BasePiece Moved(Position offset) {
        return BasePiece(position.add(offset), shape);
    }

    public BasePiece Rotated() {
        return BasePiece(position, shape.Rotated());
    }
}

但是,我希望通过移动和旋转来返回继承这个类的类的实例。我对Java比较陌生,并且有一些C#的经验,我尝试做以下事情:

代码语言:javascript
复制
public <T extends BasePiece> T Moved(Position offset) {
    return T(position.add(offset), shape);
}

public <T extends BasePiece> T Rotated() {
    return T(position, shape.Rotated());
}

有什么方法可以做到这一点吗?我最初解决这个问题的尝试是使形状和位置不再是最终的,并使移动和旋转的移动和旋转方法改变这种状态。我真的想让对象变得不可变,因为这将使我的应用程序的许多剩余部分更易于管理

EN

回答 2

Stack Overflow用户

发布于 2014-02-10 05:02:11

我认为这与泛型没有多大关系。您可以将方法的声明保留为:

代码语言:javascript
复制
public BasePiece Moved(Position offset) {
        return BasePiece(position.add(offset), shape);
}

在扩展它的类中:

代码语言:javascript
复制
class ExtendPiece extends BasePiece {

    @Override
    public BasePiece Moved(Position offset) {
            return ExtendPiece(position.add(offset), shape);
    }

}

可以由ExtendPiece向下转换为BasePiece

但是,当然,您必须自己进行强制转换:

代码语言:javascript
复制
ExtendPiece e = (ExtendPiece) obj.Moved(..);

编辑:

一种快速的解决方法是使用所谓的双重分派:

让每个子类实现方法newInstance(),这些方法在基类中是抽象的。在ExtendedPiece中:

代码语言:javascript
复制
public BaseClass newInstance(Position pos, Position[] initialShape){
    return new ExtendedPiece(pos, initialShape);
}

抽象方法的代码如下:

代码语言:javascript
复制
public BasePiece Moved(Position offset) {
     return this.newInstance(position.add(offset), shape);
}
票数 1
EN

Stack Overflow用户

发布于 2014-02-10 05:50:40

我假设您只想在基类中定义一次泛型方法,并让它们在子类中自动工作。

是的,这可以在Java中完成。它比在C#中更冗长一些,但下面是您如何做到这一点。

首先,您必须将以下代码添加到基类声明中:

代码语言:javascript
复制
public abstract class BasePiece<T extends BasePiece<T>> implements Serializable {
    ...
}

然后,在你的方法中,这样做(它涉及到反射,你必须导入java.lang.reflect.Constructor):

代码语言:javascript
复制
public T Moved(Position offset) {
        //Use reflection to invoke the constructor
        @SuppressWarnings("unchecked")
        Constructor<T> constructor = (Constructor<T>) this.getClass().getConstructor(Position.class, Position[].class);
        T newInstanceOfSpecificType = null;
        try {
            // Cast result to T, which will be the subclass
            newInstanceOfSpecificType = (T) constructor.newInstance(position.add(offset), shape);
        } catch (Exception e) {
            if (e instanceof NoSuchMethodException) {
                throw new RuntimeException("You forgot to declare the appropriate constructor in " + this.getClass().getSimpleName() + "!\n");
            }
            e.printStackTrace();
        }
        return newInstanceOfSpecificType;
    }

唯一需要注意的是:您必须确保在所有子类中定义带有签名(Position,Position[])的构造函数,并且必须明确声明您的子类,如下所示:

代码语言:javascript
复制
public class ExtendedPiece extends BasePiece<ExtendedPiece> {

    public ExtendedPiece(Posistion position, Position[] shape) {
        return super(position, shape);
    }

}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21664959

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档