接口中的泛型方法返回未经检查的强制转换

时间:2017-03-22 23:38:59

标签: java spring generics interface casting

所以我有一系列相关的接口,其中包含其他3个(由setter和getter强制执行)。

enter image description here

虽然这些接口的实例可以在管理(从地图存储和检索)时保持为接口合同;当他们到达处理bean时,他们需要能够将自己显示为自己实现的类。

所以我能够做到以下几点:

public interface IState<S extends IState> {
<G extends GameData> G getGameData();
<G> S setGameData(G gameDataIO);

<P> P getPlayer();
<P> S setPlayer(P player);

<GS> GS getGameState();
<GS> S setGameState(GS gameState);}

默认实施:

public class DefaultStateNG implements IStateNG<DefaultStateNG> {

private GameData gameDataIO;
private IPlayerState player;
private IGameState gameState;


@Override
public <G extends GameData> G getGameData() {
    return (G) gameDataIO;
}

@Override
public <G> DefaultStateNG setGameData(G gameDataIO) {
    this.gameDataIO = (GameData) gameDataIO;
    return this;
} //..... other accessor methods implemented

因此,当我在处理器bean中使用它们时,它们不需要被转换为适当的接口实现。

当在返回类型中进行转换时未经检查的强制转换时出现问题。我不知道如何处理这种警告。我的意思是我将gameDataIO设置为游戏数据类型,并且返回应该是GameData类型。为什么警告?我尝试了各种类型的转换,到目前为止唯一一个没有警告的方法就是将期望的类作为参数传递,然后使用type.cast(returnedObject)。

任何提示都将受到赞赏。

2 个答案:

答案 0 :(得分:3)

当您的界面定义如下通用方法时:

<G extends GameData> G getGameData();

编译器知道<G>必须扩展或实现GameData,但G代表的完全实现将在代码的站点处推断出来。 调用 getGameData()方法。

实施该方法时:

@Override
public <G extends GameData> G getGameData() {
    return (G) gameDataIO;
}

您在此处的实施知道 nothing 有关任何潜在的呼叫网站。它应该返回调用者(G)所需的特定子类型,它无法执行。您正在进行投射,但编译器无法验证它的安全(因为它不是),因此您获得未选中警告。

假装写一个班级MyGameData extends GameData并将其写在我的代码中:

IState<?> state = ... // TODO
MyGameData mgd = state.getGameData();

在这种情况下,<G>绑定到特定的类型MyGameData,它符合您必须从GameData继承的API要求。但是,然后你的代码返回一个普通的GameData 而不是 我的特定子类,并在运行时产生一个ClassCastException。

大多数其他方法也是如此。要么返回基本类型(GameData等),不要制作getter等,通用方法你必须添加类型参数GGSPIState界面,而不是基于每个方法。

根据此评论添加编辑:

  

GameData,Player和其他接口,其实现由Spring在启动时注入。所以我有接口只是为了确保基本功能,但处理器需要知道实现的类。我做了没有泛型的第一个版本,但我结束了大量的类型转换,使得代码不可读。

您正在描述紧密耦合系统的症状。 Interfaces are a tool用于定义松散耦合的系统,因为这些系统通常被认为是更好的设计。我鼓励您考虑为什么在您的设计中处理器需要了解其他接口的实现类型。是因为接口本身并不能完全描述该接口实现所需的功能行为吗?

答案 1 :(得分:0)

好吧,我找到了解决方案,即在实现的处理器的入口点上定义类型。我无法找到使用泛型方法设置类型声明的方法(至少没有必须进行未经检查的转换)。

William之后我很清楚必须做出声明,并且我的处理器bean是所有其他bean连接在一起的地方,因此有意义的是声明了类型。对我来说不幸的是,状态是我的处理方法的I / O对象,因此它还需要在处理器中声明包含它的类。

类似的东西:

@Component
public class KenoManager implements IGenericGame<DefaultState<
    KenoData,
    DefaultPlayer,
    KenoGameState,
    DefaultSystemState>> {

public DefaultState processInit(DefaultState<
        KenoData,
        DefaultPlayer,
        KenoGameState,
        DefaultSystemState> state) {
    return null;
}

当它来配置文件时我可以使用通配符吗?填写声明并使某些豆类注入通用。