【问题标题】:Preserving the subtype of a parameter in Java without knowing it (or how to find it?)在 Java 中保留参数的子类型而不知道它(或如何找到它?)
【发布时间】:2014-11-02 02:40:12
【问题描述】:

我的 Java 生锈了,这让我彻底崩溃了。我相信答案很简单,但这里有一个简单的示例方法,可以关闭一个 Thingy(如果已经打开),另一个打开:

private Thingy store;
public void switchiton(final Thingy pThingy) {
    if (store != null)
        store.endit();
    pThingy.startit();
    store = pThingy;
}

问题:pThingy 可能是子类(例如CleverThingy)而不是超类(Thingy),并且CleverThingy 覆盖了endit 方法。

该代码将始终在 Thingy 中运行 endit 方法 - 而不是在 CleverThingy 中被覆盖的方法(因为它被声明为 Thingy 而不是 CleverThingy)。

显然,该方法不知道(也不应该需要)子类。

我错过了什么盯着我的脸?

更新:

在这种情况下,子类是“动态”创建的(不确定正确的术语),而不是正式扩展 - 例如在我的Game 课程中:

startthingy = new Thingy();
gamethingy = new Thingy() {
    @Override
    public void endit() {
        // override things in here
        super.endit();
    }
}

switchiton(gamethingy);  // DOES call gamethingy's overridden startit
switchiton(startthingy); // << gamethingy's overridden endit is NOT called!?

【问题讨论】:

  • store 具有对CleverThingy 实例的引用值时,调用store#endit 将执行CleverThingy#endit 如果被正确覆盖。我不太清楚你的问题。
  • 我也没有,因为我刚刚花了一个小时调试的示例没有这样做(它是正确的子类型 - 它没有调用子类型方法!)一个小因素我错过了 - 参数被声明为 Final (因为后面的代码中有一个 Runnable ) - 这很重要(编辑了问题)
  • 不,没关系。请提供必要的代码来复制问题。
  • 我刚刚删除了所有线程(这是一个 LibGDX 游戏),但问题仍然存在 - 唯一的其他因素是子类被声明为“动态”(不确定正确的术语) - 我将其添加到问题中
  • 子类被声明为“动态”你的意思是它是一个匿名类,或者你使用像 cglib 这样的库来动态创建类?

标签: java parameters subclassing


【解决方案1】:

我认为最简单的解决方法是自己回答......

评论者确认我认为它应该如何工作是它实际上应该如何工作 - 这意味着错误显然在代码的其他地方......

我将重新编写所有匿名类以使它们更易于调试并更改其中一些更可疑的行为,以期跟踪错误

我问的核心问题 - 并不是真正的问题,所以......

谢谢!

【讨论】:

    【解决方案2】:

    我不知道这是否正是您正在寻找的答案(因为它更改了 Thingy 类而不是 switchItOn() 方法),但我认为我找到了一个相当简单且安全的解决方案来解决您的问题。如果您担心有人扩展了 Thingy 并且没有正确执行 endit() 方法需要做的任何事情,您可以将其定为最终版本。这将使得在 endit() 方法中需要做的任何事情都将始终完成,并且该方法不能被覆盖。

    如果您仍然希望子类能够具有该类的灵活性,您可以尝试以下操作:

    public class Thingy {
    
        public void storeIt() {
            //do stuff
        }
    
        public final void callEndIt() {
            //do whatever stuff needs to be done every time in order for your program to work
            endIt();
        }
    
        public void endIt() {
            //this can be extended by subclasses safely
        }
    
    }
    

    然后,您可以随时调用 callEndIt() 而不是 endIt(),这样您需要完成的任何安全预防措施都会得到满足。

    【讨论】:

    • 我的问题有点相反-它正在调用超类endit-但它没有调用我期望它做的被覆盖/子类的endit(并且确实调用了super.endit( )) 好主意!
    • 如果您使用的是 Eclipse,如果 GameThingy 中的 endit() 方法确实覆盖了 Thingy 的 endIt() 类,您应该会看到一个向上指向的绿色三角形。有吗?
    • 我没有在 Thingy 上看到绿色三角形,但我怀疑这是因为它在不同的包中 - 如果我使用 F3 从覆盖的方法中进行跟踪,它仍然可以工作......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-24
    • 2021-12-08
    • 2021-10-22
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多