【问题标题】:Why are these hidden static methods sometimes not detected?为什么有时检测不到这些隐藏的静态方法?
【发布时间】:2013-10-31 15:14:48
【问题描述】:

抱歉标题含糊;我不完全确定问题出在哪里。

背景

简而言之:某个基类的子类必须定义 3个特定的静态方法,隐藏基类的静态方法。实现描述类在初始化时检查这一点。然而,在运行应用程序时似乎是随机的,但是在初始化期间我得到运行时异常,说我没有正确地重新实现这些方法。但是,当这种情况发生时,我正在其他地方从事不相关的课程,这种情况很少发生,并且只需打乱方法的顺序即可将其修复很长时间。

代码

所以,三个类:Base、Derived 和 AlgImplementation 类:

AlgImplementation 构造函数:

/* verifying that the extending class has implemented these methods */
        if (this.getAlgorithmClassName() == null) {
            throw new IllegalArgumentException("The Algorithm Class of this algorithm has not re-implemented the getAlgorithmClassName() method from as specified.");
        }
        if (this.getAlgorithmClassDescription() == null) {
            throw new IllegalArgumentException("The Algorithm Class of this algorithm has not re-implemented the getAlgorithmClassDescription() method from as specified.");
        }
        if (this.getAlgorithmClassAnalyticLevel() == null) {
            throw new IllegalArgumentException("The Algorithm Class of this algorithm has not re-implemented the getAlgorithmClassAnalyticLevel() method from as specified.");
        }

这就是问题发生的地方,其中一项检查失败了。我从上述一项或多项中得到 IllegalArgumentException。我可以简单地在派生类中移动实现的顺序,强制重新构建该代码,然后它就可以正常工作了。

基类和派生类都具有相同的简单静态方法,但它们返回的静态字段的定义不同:

class Derived extends Base {
public static AnalyticLevel getAlgorithmClassAnalyticLevel()
    {
        return ANALYTIC_LEVEL;
    }

    public static String getAlgorithmClassName()
    {
        return NAME;
    }

    public static String getAlgorithmClassDescription()
    {
        return DESCRIPTION;
    }
 }

以上字段都是非空的静态final Strings。

现在,在 Derived 类中,我声明了一个静态最终 AlgImplementation 字段: public static final AlgImplementation derivedAlg = new AlgImplementation("xyz", Derived.class, "我们的 XYZ 派生类", "");

最后,我认为您需要知道的最后一件事是,此 AlgImplementation 实例为每个静态方法类执行此操作:

public String getAlgorithmClassName() {
        String className = "";
        try {
            className = (String)algorithmClass.getDeclaredMethod("getAlgorithmClassName", new Class<?>[0]).invoke(null, new Object[0]);
        } catch (Exception e) {
            throw new UnsupportedOperationException("Required static method getAlgorithmClassName() not implemented on "+this.getClass().getName());
        }
        return className;
    }

终于

所以,我的问题是:如果实际上声明了这些方法,那么对派生方法的检查怎么会失败?声明一个引用它所定义的类的静态 AlgImplementation 字段是否存在问题(导致一些奇怪的编译顺序或类似问题)?

错误是在 Derived 类的初始化过程中,特别是在初始化静态 AlgImplementation 字段的那一行,这就是为什么我认为在 Derived 类本身中这样做可能存在问题。

【问题讨论】:

  • 您不能派生、重载或覆盖静态方法。您通常通过类限定符访问它们
  • 我用错了词,编辑为“定义”而不是“覆盖”。派生类隐藏基类方法。
  • 您得到的是哪个错误,IllegalArgumentException 还是 UnsupportedOperationException?
  • IllegalArgumentException

标签: java inheritance dynamic static


【解决方案1】:

我怀疑问题是由于类的静态最终字段的初始化顺序造成的。通过在类初始化期间使用反射,您可以在类完全初始化之前访问它。如果在派生类上,您有以下内容:

public static final String NAME;
static {
    NAME = "some name";
}

public static final AlgImplementation derivedAlg =
    new AlgImplementation("xyz", Derived.class, "Our XYZ derived class", "");

然后 AlgImplementation 将在初始化后检查 NAME 常量,并读取“some name”字符串。如果您颠倒顺序:

public static final AlgImplementation derivedAlg =
    new AlgImplementation("xyz", Derived.class, "Our XYZ derived class", "");

public static final String NAME;
static {
    NAME = "some name";
}

然后 AlgImplementation 将在常量被分配之前读取它,并改为读取 null

如果 NAME 是由这样的编译时常量直接分配的,我不确定是否可能发生这种情况:

public static final String NAME = "some name";

我猜想这会阻止这个问题,但也许不会。您关于“改组方法的顺序将其修复很长时间”的说法支持了问题是由于初始化顺序引起的想法。我建议将 derivedAlg 字段移到所有其他常量之后,以鼓励它最后初始化。

【讨论】:

  • 是的,很简单。虽然测试很烦人,因为这些运行时故障很少发生(并且要求我每次都去测试某个部分来初始化它),但主要是因为我正在处理一个不相关的部分,但其他人都认为我疯了当我说他们的代码有时会失败时。在我去打鹅之前,我会看看我是否能找到任何关于初始化顺序的规范。
  • @Nick 这种静态方法覆盖技术有充分的理由吗?从您显示的代码部分来看,您似乎可以直接将所需信息传递给 AlgImplementation 而无需反射:public static final AlgImplementation derivedAlg = new AlgImplementation(ANALYTIC_LEVEL, NAME, DESCRIPTION)
  • 我不知道。代码相当复杂。我仍然在学习很多东西。但是,我不能将详细信息传递给 AlgImplementation 实例。无论如何,快速浏览docs.oracle.com/javase/specs/jls/se7/html/…,看起来非常量值的初始化是线程化的,所以我有一个竞争条件。
  • 所以,据我所知,这就是问题所在。这说得通。我无法修改大部分代码,但我创建了一个管理器类来处理所有AlgImplementations,而不是将它们放在它引用的每个类中。这似乎解决了我的问题。没碰到过,试了一段时间。
【解决方案2】:

静态方法不参与类层次结构。您应该始终使用staticMethod()Class.staticMethod()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 2011-11-23
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    • 2019-08-07
    • 2012-11-07
    相关资源
    最近更新 更多