简体   繁体   English

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

[英]Performance/treatment of static references to class instances

I've been toying with the following java pattern lately, it's helped solve a few code organization issues but I have multiple questions about best practices, performance, etc. 我最近一直在尝试以下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];
    }
}

The class registers a list of things to static variables, but has a private constructor also saving a list by id # to an array. 该类将事物列表注册到静态变量,但具有私有构造函数,该构造函数还将ID号列表保存到数组中。 Minecraft is one example of where this is used in the wild - for their item class "registry". Minecraft是在野外使用它的一个例子-对于他们的物品类别“注册表”。

A few questions: 几个问题:

  • If there's no single instance of Example saved anywhere outside this, do calls to either Example.somethingOne or Example.getById() re-run all of this code, or is this all just run once? 如果在此之外的任何地方都没有保存Example的单个实例,请调用Example.somethingOneExample.getById()重新运行所有这些代码,还是只运行一次? Maybe I'm missing some understanding of static ? 也许我缺少对static了解?
  • Is there any reason why you'd want the static instances of somethingOne to be public, rather than just calling it by id? 是否有任何理由为什么你要的静态实例somethingOne是公开的,而不是仅仅通过ID调用它? Seems like getById is friendly if you have mods/plugins added custom items to the list that do not have static references by name here. 如果您有mods / plugins将自定义项目添加到列表中,但此处没有按名称静态引用,则好像getById是友好的。

If there's no single instance of Example saved anywhere outside this, do calls to either Example.somethingOne or Example.getById() re-run all of this code, or is this all just run once? 如果在此之外的任何地方都没有保存Example的单个实例,请调用Example.somethingOne或Example.getById()来重新运行所有这些代码,还是只运行一次? Maybe I'm missing some understanding of static? 也许我缺少对静态的一些了解?

No, static blocks are run at class load time and are tied to the instance of java.lang.Class which represents the class itself. 不,静态块在类加载时运行,并绑定到代表类本身的java.lang.Class实例。

Classes are lazily loaded, but once loaded, never reload within the life of their class loader. 类是延迟加载的,但是一旦加载,就永远不会在其类加载器的生存期内重新加载。

There is no performance loss by calling a static method or accessing a static variable instead of using an instance of it. 通过调用静态方法或访问静态变量而不使用其实例不会造成性能损失。

Is there any reason why you'd want the static instances of somethingOne to be public, rather than just calling it by id? 您是否有任何理由想要公开someone的静态实例,而不是仅通过id调用它? Seems like getById is friendly if you have mods/plugins added custom items to the list that do not have static references by name here. 如果您有mods / plugins将自定义项目添加到列表中,但此处没有按名称静态引用,则好像getById是友好的。

You kind of answered your own question here. 您在这里回答了自己的问题。 Running access through a method enables the future addition of modules/plugins or some other work without having to refactor calling code. 通过一种方法运行访问可以在将来添加模块/插件或进行其他一些工作,而不必重构调用代码。

One reason, however, that I may want the instances to be static members is if calling code needs to interact with specific instances and not others and you simply want your class to be able to control what those instances are, perhaps so you can add new instances when you want to. 但是,我可能希望实例成为静态成员的一个原因是,如果调用代码需要与特定实例而不是其他实例进行交互,而您只是希望您的类能够控制那些实例,那么也许您可以添加新的实例。您想要的实例。

Enums are a good example of this. 枚举就是一个很好的例子。

I have used the exact pattern you have above for a dynamic enum, where what I wanted was an enum, but I needed certain instances to be of sub-types and clients to not worry about it. 对于动态枚举,我已经使用了上面的确切模式,我想要的是一个枚举,但是我需要某些实例属于子类型,并且客户不必担心它。

Since the only place where the private constructor is invoked is in the static declaration of somethingOne and somethingTwo , this constructor will be invoked the first time the class is used, which is what would trigger the loading of the class and the execution of the static code. 因为调用私有构造函数的唯一位置是在somethingOnesomethingTwo的静态声明中,所以该构造函数将在第一次使用该类时被调用,这将触发该类的加载和静态代码的执行。 。

This would execute every time the class is initialized, which means that in a typical scenario where you use the default class loading provided by Java, this would only be invoked once no matter how many times you access the fields. 这将在每次初始化类时执行,这意味着在典型情况下(使用Java提供的默认类加载),无论您访问字段多少次,都只会调用一次。

You may want to read the JLS 12.4 Initialization of Classes and Interfaces and JVMS 5.5 Initialization . 您可能需要阅读类和接口JLS 12.4初始化JVMS 5.5初始化

Not sure why the static instances are public, they could perfectly be private static final and by invoking the getId method the first time you would trigger the initialization of the class and obtain the same results. 不确定为什么静态实例是公共的,它们可以完全是私有的static final,并在第一次触发类的初始化并获得相同结果时调用getId方法。 Maybe this is just convenience, after all the fields are static and final, so why not provide direct access to them? 在所有字段都是静态字段和最终字段之后,也许这只是方便,所以为什么不提供对它们的直接访问?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM