是否可以在Java中阻止/拒绝强制转换?

Dav*_*les 9 java casting

我有一个简单游戏的代码,其中必须实现AgentInterface才能为游戏中的一个角色创建代理控制器.GameState是一个实现GameStateInterface的类,实现此接口的对象可以传递给代理,因此代理可以从游戏状态读取和分析数据,并且代理必须返回相应的操作(作为int返回)角色应该采取.

这是代理必须实现的AgentInterface:

public interface AgentInterface {
    // the return value specifies the direction of the joystick
    public int action(GameStateInterface gs);
}
Run Code Online (Sandbox Code Playgroud)

使用名为MyAgent的代理运行游戏:

    GameState gs = new GameState();
    AgentInterface agent = new MyAgent();
    while (true) {
        // more code here
        int bestAction = agent.action(gs)
        // more code here
    }        
Run Code Online (Sandbox Code Playgroud)

但是,GameState中存在一些代理无法访问的信息,因为这会欺骗控制器.但是,执行从GameStateInterface到GameState的转换转换将允许代理访问GameStateInterface中未定义的信息,如下所示:

public MyAgent implements AgentInterface {
    public int action(GameStateInterface gs) {
        int nLives = ((GameState) gs).nLivesRemaining; // IS IT POSSIBLE TO DENY/PREVENT THIS CAST??
        // Do more stuff here
        return BestAction;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否可以阻止转换?我知道多态性是Java和面向对象编程语言的主要特性之一,但在这种情况下我想避免转换.

我知道这可以通过许多其他方式解决,但我很想知道是否可以这样做.

提前致谢.

Sim*_*ann 12

据我所知,不可能拦截类型转换并拒绝它(例如,通过抛出ClassCastException).

但是,您可以简单地使用代理模式来控制对实际GameState对象的访问,而不是试图拒绝类型转换.只需实现一个代理类,它只实现GameStateInterface并让它将所有方法调用转发给GameState对象.现在,不是将实际的GameState对象引用传递给action方法,而是将它传递给代理类的实例.

  • 警告 - 确保已配置Java安全性,以便代理(即不可信)代码无法使用Reflection API.有些人可以使用反射来访问代理类的私有成员来获取GameState对象. (4认同)

Jay*_*rod 5

通常,您不能阻止在Java中强制转换对象。收到对您的引用的代码GameState将能够在该对象上调用任何非私有,不受保护的方法。即使可以防止投射,它仍然可以使用反射。

如果Agent代码在您的控制之下,则只需保持简单即可,不要进行转换。如果其他人编写Agent类,则可以创建一个代理类,该代理类接受GameState对象,并且仅实现GameStateInterface的方法。

class GameStateProxy implements GameStateInterface {
    private GameStateInterface state;

    public GameStateProxy(GameState state) {
        this.state = state;
    }

    public int someMethodInGameStateInterface(int x) {
        return state.someMethodInGameStateInterface(x);
    }

    // other methods ...
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建一个代理并像这样传递它:

GameStateInterface proxy = new GameStateProxy(gameState);
int bestAction = agent.action(proxy);
Run Code Online (Sandbox Code Playgroud)

接收a的代码GameStateProxy只能访问中的方法GameStateInterface

  • 但请记住将SecurityManager设置为禁止反射。获得私有状态不是难事... (3认同)