【问题标题】:Performance/treatment of static references to class instances对类实例的静态引用的性能/处理
【发布时间】:2013-09-08 04:35:52
【问题描述】:

我最近一直在玩弄下面的 java 模式,它帮助解决了一些代码组织问题,但我有很多关于最佳实践、性能等方面的问题。

public class Example {

    private static int[] somethingList = int[128];

    public static final Example somethingOne = new Example(1);
    public static final Example somethingTwo = new Example(2);
    public static final ExampleChild somethingThree = new ExampleChild(3); // ExampleChild would extend Example

    private Example( int id ){
        // checks for existing id, etc
        somethingList[id] = this;
    }

    public static Example getById( int id ){
        return somethingList[id];
    }
}

该类将事物列表注册到静态变量,但有一个私有构造函数也将通过 id # 的列表保存到数组中。 Minecraft 是在野外使用它的一个例子 - 用于他们的项目类“注册表”。

几个问题:

  • 如果在此之外的任何地方都没有保存 Example 的单个实例,是否调用 Example.somethingOneExample.getById() 重新运行所有这些代码,还是只运行一次?也许我对static 缺少一些了解?
  • 您有什么理由希望somethingOne 的静态实例是公开的,而不是仅仅通过ID 调用它?似乎getById 是友好的,如果你有模组/插件添加自定义项目到列表中,这里没有静态引用。

【问题讨论】:

  • 这是您正在做的事情的精简示例吗?因为您在此处显示的内容应该使用 Java 枚举来完成。
  • 这显然是一个纯粹的例子,但 ENUM 的主要问题是它们无法扩展。这允许添加第三个选项,它实际上是任意数量的子类,它扩展了 Example

标签: java performance static


【解决方案1】:

如果在此之外的任何地方都没有保存 Example 的单个实例, 调用 Example.somethingOne 或 Example.getById() 重新运行 所有这些代码,还是只运行一次?也许我错过了一些 对静态的理解?

不,静态块在类加载时运行,并与代表类本身的 java.lang.Class 实例绑定。

类是延迟加载的,但一旦加载,就不会在其类加载器的生命周期内重新加载。

调用静态方法或访问静态变量而不是使用它的实例不会造成性能损失。

你有什么理由想要静态实例 somethingOne 要公开,而不仅仅是通过 id 调用它?似乎 如果你有 mods/plugins 添加自定义项目,像 getById 一样友好 到这里没有静态引用的列表。

您在这里回答了自己的问题。通过方法运行访问可以在将来添加模块/插件或其他一些工作,而无需重构调用代码。

然而,我可能希望实例成为静态成员的一个原因是,如果调用代码需要与特定实例而不是其他实例进行交互,并且您只是希望您的类能够控制这些实例是什么,也许这样您可以根据需要添加新实例。

枚举就是一个很好的例子。

我已经将上面的确切模式用于动态枚举,我想要的是一个枚举,但我需要某些实例是子类型并且客户端不用担心它。

【讨论】:

  • 谢谢 - 这清楚地回答了这两个问题。我很高兴这是一个有用的模式,我总是在猜测是否有更好的模式来满足我的需要。
  • +1 当您对性能问题感到疑惑时,您应该坚持使用最简单、最清晰的解决方案,并且只有在您测量到真正的差异时才更改性能代码(而不仅仅是猜测哪个经常让事情变得更糟)
【解决方案2】:

由于调用私有构造函数的唯一地方是在somethingOnesomethingTwo的静态声明中,所以这个构造函数将在第一次使用类时被调用,这会触发类的加载以及静态代码的执行。

这将在每次初始化类时执行,这意味着在您使用 Java 提供的默认类加载的典型场景中,无论您访问字段多少次,它都只会被调用一次。

您可能想阅读JLS 12.4 Initialization of Classes and InterfacesJVMS 5.5 Initialization

不确定为什么静态实例是公共的,它们完全可以是私有的 static final 并且通过在第一次调用 getId 方法时触发类的初始化并获得相同的结果。也许这只是方便,毕竟所有字段都是静态和最终的,那么为什么不提供对它们的直接访问呢?

【讨论】:

  • 谢谢,我主要是想确保如果我的代码调用 Example.somethingOne,然后是 Example.somethingTwo,所有这些新的 Example 实例不会在我每次调用时都被重新实例化.
  • 您的字段由您的类初始化,无论您访问它们多少次,都只初始化一次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
  • 2011-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多