关于java:根据输入枚举值返回一个转换对象

Returning a casted object based on input Enum value

我正在尝试创建一个方法,该方法获取枚举值并返回一个基于该枚举值强制转换为类的对象。例如,我有一个名为componenttype的枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
    }
}

"healthcomponent"和"hungercomponent"是两个扩展名为"component"的类的类。在这个问题上,他们内心的东西并不重要。

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

我的目标是在实体内部创建一个方法,当传入component type枚举中的值时,将返回一个组件对象,该对象被强制转换为该值的相应类类型。因此,如果传入componenttype.health,该方法将返回一个强制转换为healthcomponent的对象。这是我正在尝试的,但它不起作用:(编辑:见下文)

1
2
3
4
5
6
7
8
9
10
11
12
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类型时:

1
entity.getComponentByType(ComponentType.HEALTH);

将返回强制转换为"component"而不是"healthcomponent"的对象。我希望它返回一个转换为healthcomponent的对象,而不是组件。

有什么办法吗?我觉得这是可能的。我之所以想找到一种方法来做到这一点,是因为它看起来像是在做所有这些演员:

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

这有点浪费,因为方法可以(希望)假定我希望通过传入的componentType强制转换的内容。

编辑(详细信息):

仔细观察结果,我注意到我的方法在某些方面有效。我的意思是,在Eclipse中,如果我键入:

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

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

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

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

然后将鼠标悬停在getcomponentbytype上,查看它返回的是什么,它说它返回 HealthComponent,并且它编译并运行。所以从技术上讲是可行的,但不是按照我希望的方式。这是一个小问题,因为如果我在第一个示例中告诉Eclipse为我创建一个局部变量,它将创建一个类型为"component"的变量,我必须手动更改它。


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

不幸的是,您不能将类型参数添加到枚举值中(参见本问题),但是如果您再次查看自己的代码,您可能会意识到您已经有了一个对象,该对象恰当地描述了您想要获取的组件,并且正好包含了我们需要的类型信息:每个组件类型的Class<>对象!

所以,这是我对您的功能的建议(没有编译或测试,请注意,我的Java可能生锈):

1
2
3
4
5
6
7
8
9
10
11
public <T extends Component> T getComponentByType(Class<T> type)
{
    for(Component component : componentList)
    {
        if(component.getClass() == type)
        {
            return (T)component;
        }
    }
    return null;
}


我迟到了4年,但我遇到这个问题是因为我遇到了类似的情况,想要一个好的解决方案。

可以通过给枚举一种提取和强制转换的方法来解决这个问题,而不是依赖一个试图找出类型的实体。

例如,可以向componenttype枚举添加如下方法:

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

稍后不再尝试:

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

你可以写这样的东西

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

在我的例子中,我希望有一个带有枚举键的映射,并使用如下解决方案:

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