性能/处理对类实例的静态引用

时间:2013-09-08 04:35:52

标签: java performance static

我最近一直在玩弄以下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.somethingOneExample.getById()重新运行所有此代码,还是只运行一次?也许我对static
  • 缺乏了解
  • 是否有任何理由要求somethingOne的静态实例是公开的,而不是仅仅通过id调用它?似乎getById是友好的,如果你有mods / plugins添加到列表中的自定义项目,这里没有名称的静态引用。

2 个答案:

答案 0 :(得分:4)

  

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

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

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

通过调用静态方法或访问静态变量而不是使用它的实例,没有性能损失。

  

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

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

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

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

我已经使用了上面用于动态枚举的确切模式,其中我想要的是枚举,但我需要某些子类型和客户端实例而不用担心它。

答案 1 :(得分:0)

由于调用私有构造函数的唯一位置是somethingOnesomethingTwo的静态声明,因此第一次使用该类时将调用此构造函数,这将触发加载类和执行静态代码。

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

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

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