基于输入枚举值返回转换对象

时间:2014-10-17 20:57:32

标签: java generics casting enums

我正在尝试创建一个接受Enum值的方法,并返回一个基于该Enum值转换为类的对象。例如,我有一个名为ComponentType的Enum:

public enum ComponentType
{
    HEALTH(HealthComponent.class),
    HUNGER(HungerComponent.class);

    private Class<? extends Component> componentClass;

    private ComponentType(Class<? extends Component> componentClass)
    {
        this.componentClass = componentClass;
    }

    public Class<? extends Component> getComponentClass()
    {
        return componentClass;
    }
}

&#34; HealthComponent&#34;和&#34; HungerComponent&#34;是两个类,它们都扩展了一个名为&#34; Component&#34;的类。其中的内容对于这个问题并不重要。

实体将拥有一个他们被分配的组件列表(例如,一个实体可能有饥饿,而另一个实体可能有健康,另一个可能有两个实体)。

我的目标是在Entity中创建一个方法,当传入ComponentType Enum中的值时,会返回一个Component对象,该对象被转换为该值的相应类类型。因此,如果您传入ComponentType.HEALTH,该方法将返回一个转换为HealthComponent的对象。这是我正在尝试的,但它不起作用:(编辑:见下文)

public <T extends Component> T getComponentByType(ComponentType type)
{
    Class<? extends Component> componentClass = type.getComponentClass();
    for(Component component : componentList)
    {
        if(component.getClass() == componentClass)
        {
            return (T) componentClass.cast(component);
        }
    }
    return null;
}

对于上面的方法,当传入一种ComponentType.HEALTH:

entity.getComponentByType(ComponentType.HEALTH);

一个对象被转换为&#34;组件&#34;而不是&#34; HealthComponent&#34;将被退回。我希望它返回一个转换为HealthComponent的对象,而不是Component。

有没有办法做到这一点?我觉得这应该是可能的。我试图找到一种方法来实现这一点的原因是因为它似乎在做所有这些演员:

HealthComponent component = (HealthComponent) entity.getComponentByType(ComponentType.HEALTH);

有点浪费,因为该方法可以(希望)假设我想通过传入的ComponentType来强制转换。

修改(更多信息):

仔细研究一下结果,我注意到我的方法有些可行。我的意思是在Eclipse中,如果我输入:

component = entity.getComponentByType(ComponentType.HEALTH);

(组件变量尚未定义)然后将鼠标悬停在getComponentByType上以查看它返回的内容,它表示它正在返回<Component> Component

但是,如果我手动定义变量类型(大多数时候我只是让Eclipse为我创建变量),如下所示:

HealthComponent component = entity.getComponentByType(ComponentType.HEALTH);

然后将鼠标悬停在getComponentByType上以查看它返回的内容,它表示它正在返回<HealthComponent> HealthComponent并且它会编译并运行。所以它在技术上有效,但不是我喜欢的方式。这是一个小问题,因为如果我告诉Eclipse在第一个例子中为我创建一个局部变量,它将创建一个类型&#34; Component&#34;的变量。我必须手动更改。

2 个答案:

答案 0 :(得分:2)

您希望编译时返回类型getComponentByType()取决于用于选择组件的参数。这可以通过泛型来实现,但前提是参数实际上包含了您需要的编译时类型信息。

不幸的是,您无法将类型参数添加到枚举值(请参阅this question),但如果您再次查看自己的代码,您可能会发现您已经有一个适当描述哪个组件的对象你想得到的,这恰好带有我们需要的类型信息:每个组件类型的Class<>对象!

所以,这是我对你的功能的建议(没有编译或测试,要小心,我的Java可能会生锈):

public <T extends Component> T getComponentByType(Class<T> type)
{
    for(Component component : componentList)
    {
        if(component.getClass() == type)
        {
            return (T)component;
        }
    }
    return null;
}

答案 1 :(得分:0)

我参加聚会晚了4年,但是我遇到了这个聚会,因为我遇到了类似的情况,并希望找到一个好的解决方案。

可以通过为枚举提供一种提取和转换的方式来解决此问题,而不是依赖于试图找出类型的实体。

例如,您可以像这样将方法添加到ComponentType枚举中:

public <C extends Component> C fromEntity(Entity entity) {
    List<Component> componentList = entity.getComponentList();
    // add your existing iteration and type casting logic here
}

然后稍后不要尝试:

HealthComponent component = (HealthComponent) entity.getComponentByType(ComponentType.HEALTH);

您可以这样写

 HealthComponent component = ComponentType.HEALTH.fromEntity(entity);

在我的情况下,我想要一个带有枚举键的地图,并采用这样的解决方案:

https://gist.github.com/hiljusti/5240d42e827b77e65f41f0a7dfac4406