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

是否可以在Java中阻止/拒绝强制转换?,java,casting,Java,Casting,我有一个简单游戏的代码,其中必须实现AgentInterface,以便为游戏中的一个角色创建代理控制器。GameState是一个实现GameStateInterface的类,实现该接口的对象可以传递给代理,因此代理可以读取和分析来自GameState的数据,并且代理必须返回角色应该执行的适当操作(返回为int) 这是代理必须实现的代理接口: public interface AgentInterface { // the return value specifies the direct

我有一个简单游戏的代码,其中必须实现AgentInterface,以便为游戏中的一个角色创建代理控制器。GameState是一个实现GameStateInterface的类,实现该接口的对象可以传递给代理,因此代理可以读取和分析来自GameState的数据,并且代理必须返回角色应该执行的适当操作(返回为int)

这是代理必须实现的代理接口:

public interface AgentInterface {
    // the return value specifies the direction of the joystick
    public int action(GameStateInterface gs);
}
使用名为MyAgent的代理运行游戏:

    GameState gs = new GameState();
    AgentInterface agent = new MyAgent();
    while (true) {
        // more code here
        int bestAction = agent.action(gs)
        // more code here
    }        
但是,在游戏状态中,有些信息是代理不能访问的,因为这会欺骗控制器。但是,执行从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;
    }
}
GameStateInterface proxy = new GameStateProxy(gameState);
int bestAction = agent.action(proxy);
我的问题是,是否有可能阻止演员转换?我知道多态性是Java和面向对象编程语言的主要特性之一,但在这种情况下,我希望避免强制转换

我知道这可以用很多其他的方法来解决,但我很好奇是否有可能做到这一点


提前谢谢。

不,没有办法做到这一点

最美好的祝愿,

费边

我不知道您所描述的内容在Java中是否可行。在其他语言中,您可以重载类型转换操作符并让它们抛出异常或其他东西,但在Java中这是不可能的。你最好的办法可能是用你所说的“许多其他方式”中的一种来做。

据我所知,截取类型转换并拒绝它是不可能的(比如,抛出一个ClassCastException)


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

无法阻止强制转换。但是,您可以定义游戏状态,使其只能从特定位置构建。想到的一件事是实现接口的私有内部类,或者返回私有内部类实例的工厂。答案很简单,“不要在代理代码中强制转换为游戏状态”


或者,你可以将游戏状态声明为私有。或者,如果您需要从其他几个类访问它,请将其声明为受包保护。

如果您担心代理正在更改游戏状态,请创建该状态的bean副本并将其传递给代理,而不是真正的GameState对象


禁止强制转换听起来不太可能(这可能是一个不可阻止的JVM语言规范特性),或者我从来没有听说过它。

一般来说,您不能阻止对象在Java中强制转换。接收对
游戏状态的引用的代码将能够调用该对象上的任何非私有、非保护方法。即使你可以阻止投射,它仍然可以使用反射

如果
代理
代码在您的控制之下,请保持简单,不要强制转换。如果其他人编写
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 ...
}
然后您可以创建一个代理并按如下方式传递它:

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;
    }
}
GameStateInterface proxy = new GameStateProxy(gameState);
int bestAction = agent.action(proxy);

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

我们要做的是提供一个带有“存根”的jar,您可以根据它进行编译,但它不包含任何实现。当实际产品运行时,我们用一个真正的jar替换存根

但在我们的例子中,我们控制它运行的位置

在我们的例子中,我们也完全按照你的要求去做。任何类都必须请求访问其他类(在运行时)。我相信这都是自定义实现,但我不确定它是否能在任何JVM上运行

您可以尝试查找/请求/任何我正在处理的东西的源代码。有一个参考实现,如果你说你有兴趣开发电缆盒,你可能能够得到它。它被称为“tru2way”或“OCAP”参考堆栈实现,我认为该项目可以在java站点的某个地方找到。可能需要一点谷歌搜索——我敢肯定你会发现这一切都是在一个特殊的类加载器或SecurityManager中完成的

编辑:我想我可能错了。我们所做的是根据被访问的类的名称,使用安全管理器创建“权限”。当线程试图调用类上的方法时,我们首先测试它的权限(我们在“受保护”类中编写代码),如果当前线程没有由类名称标识的权限,它将抛出异常

效果与您追求的效果相同,但速度较慢且更冗长。但是我们必须阻止孩子们看pr0n

编辑2:(对不起!!)

看着这样的权限描述,我相信这至少部分是可能的:

这将授予代码查询类的公共、受保护、默认(包)访问和私有字段和/或方法的权限。尽管代码可以访问私有和受保护的字段和方法名称,但它不能访问私有/受保护的字段数据,也不能调用任何私有方法。然而,恶意代码可能会使用此信息来更好地瞄准攻击。此外,它可以调用任何公共方法和/或访问类中的公共字段。如果代码通常无法调用这些方法和/或访问字段,因为它无法强制转换对象t,那么这可能是危险的
ItemReadOnly readOnly = item.getReadOnlyInstance();