由java中的子类类型id安全转换

时间:2010-10-14 09:14:34

标签: java casting

我有一个基础Entity类:

public class Entity
{
    abstract int getTypeID();
}

方法int getTypeID()返回该类唯一的数字:

public class OneEntity extends Entity
{
    int getTypeID()
    {
        return 1; // Actually defined in a constants class
    }
}

现在我希望能够安全地投射并分配它。

我可以这样做:

public void castTheEntityAndDoSomething(Entity ent)
{
    if (isType(ent, 1)) // this is the 1 from the OneEntity class
    {
        OneEntity oneEnt = (OneEntity)ent;

        // ... and then do something
    }
}

public bool isType(Entity ent, int type)
{
    return ent.getTypeID() == type;
}

但我想要做的是将演员表和类型检查合并在一行中。

类似的东西:

if (OneEntity oneEnt = entityCast(ent, 1))
{
    // use a method specific to the OneEntity class
}

这可能吗?该方法是什么样的? 如果我可以使用子类名作为安全转换方法的参数,那会更好。

编辑:

所以我写了这个方法以避免类型id等。

@SuppressWarnings("unchecked")
public static <T extends Entity> T castEntity(Entity ent)
{
    if (ent instanceof T)
    {
        return (T)ent;
    }

    return null;
}

但它有这个错误:

无法对类型参数T执行instanceof检查。请改为使用其擦除实体,因为泛型类型信息将在运行时被删除

我需要做些什么来解决这个编译错误?这是否正朝着正确的方向发展?

4 个答案:

答案 0 :(得分:2)

如果您仅为了投射而定义了此typeId,那么请不要这样做,而是使用instanceof运算符。

然后你只需要做这样的事情,

if (ent instanceof EntityOne) {
   OneEntity oneEntity = (OneEntity) ent;
   // do whatever
}

现在,举个例子,

if (Entity oneEnt = entityCast(ent, 1))
{
    // do something with oneEnt
}

假设您的if语句有效,而entityCast()方法返回OneEntity。你不认为你再次获得Entity类型的返回值。因此破坏了整个目的。

所以,请解释你想要做什么。

答案 1 :(得分:1)

如果你实现了一个接口来定义你想要从“do something”块调用它们的方法,并在所有派生的entiries中实现这个接口,你就可以通过使用多态来解决问题。

答案 2 :(得分:1)

您可能想重新考虑您的架构 首先,也许你不应该在课堂上有一个typeID字段 您应该依赖继承和/或接口的“强大”。

// Entity.java
public interface Entity { abstract public void doSomeThing(); }

// EntityType1.java
public class OneEntity extends Entity { 
    @Override
    public void doSomeThing() {
        // do something specific for entity type 1
    }
}

// EntityType2.java
public class TwoEntity extends Entity { 
    @Override
    public void doSomeThing() {
        // do something specific for entity type 2
    }
}

// Main.java
public static void main(String[] args) {
    Entity e1 = new EntityType1();
    Entity e2 = new EntityType2();
    e1.doSomeThing();
    e2.doSomeThing();
}

您应该在实现类中封装不同的行为。

如果您认为有充分的理由将行为与实体分离,则最好在外部处理类的层次结构中使用相同的逻辑(可能在顶部使用简单的工厂),并在工厂方法中使用“instanceof”。

答案 3 :(得分:1)

我想你可以这样做:

OneEntity oneEnt;
if (isType(ent, 1) && (oneEnt = (OneEntity) ent) != null) {
    // ... and then do something
}

...或等效于instanceof而非您的isType方法......

或者您可以按如下方式定义名为oneEntityOrNull的方法:

public OneEntity oneEntityOrNull(Entity ent) {
    return ent instanceof OneEntity ? (OneEntity) ent : null;
}

然后

OneEntity oneEnt;
if ((oneEnt = oneEntityOrNull(ent)) != null) {
    // ... and then do something
}

但IMO这两个都是一个糟糕的IDEA,因为代码比原始代码更难理解。