【问题标题】:Initialize a static final field in the constructor在构造函数中初始化一个静态最终字段
【发布时间】:2011-07-02 21:35:02
【问题描述】:
public class A 
{    
    private static final int x;

    public A() 
    {
        x = 5;
    }
}
  • final 表示变量只能赋值一次(在构造函数中)。
  • static 表示它是一个类实例。

我不明白为什么禁止这样做。这些关键字在哪里相互干扰?

【问题讨论】:

    标签: java static constructor final


    【解决方案1】:

    每次创建类的实例时都会调用构造函数。因此,上面的代码意味着每次创建实例时都会重新初始化 x 的值。但是因为变量被声明为 final (并且是静态的),所以你只能这样做

    class A {    
        private static final int x;
    
        static {
            x = 5;
        }
    }
    

    但是,如果你删除静态,你可以这样做:

    class A {    
        private final int x;
    
        public A() {
            x = 5;
        }
    }
    

    或者这个:

    class A {    
        private final int x;
    
        {
            x = 5;
        }
    }
    

    【讨论】:

    • 显然没有人愿意解释静态变量是存在于类的所有实例中的变量。因此,它们只能在类被加载时被实例化一次——而不是在类的潜在许多实例被构造时。
    • 另外,我建议只在声明中分配而不是在静态块中分配。它更干净,可能是 OP 想要做的:private static final int x = 5;
    • 如果你想从另一个组件/类传递值“5”,而不是硬编码呢?
    【解决方案2】:

    静态最终变量在加载类时初始化。构造函数可能会在很久以后调用,或者根本不调用。此外,构造函数将被多次调用(每个新对象),因此该字段不再是最终的。

    如果您需要自定义逻辑来初始化静态最终字段,请将其放在静态块中

    【讨论】:

    • 好的,但你刚刚解释了发生了什么。我问为什么?我的意思是,没有最终它可以工作,没有静态它可以工作。所以将两者结合起来会产生一些新的逻辑?
    • @YaronLevi 他刚刚说过......静态字段是类本身的成员。在您的构造函数中,您正在为变量赋值。 final 一词意味着您只能为变量赋值一次,在您的代码中,每次实例化类时都会为变量赋值 - 因为变量是静态的(类的成员)。如果您摆脱静态,那么您可以在构造函数中为其分配一个值,因为它每次都是一个新变量。如果你去掉 final 那么它只是一个静态变量,你可以随时为其分配一个新值。
    • @user12345613 提出了一个很好的解释。独自一人,无论是最终作品还是静态作品;但是一旦放在一起,“静态最终”会强制该类在所有实例中只有一个这样的字段,并且无论有多少实例,都只能初始化一次。
    【解决方案3】:

    想想第二次实例化一个对象时会发生什么。它试图再次设置它,这是一个静态决赛明确禁止的。只能为整个类设置一次,不能为实例设置。

    你应该在声明时设置值

    private static final x=5;
    

    如果您需要额外的逻辑或更复杂的实例化,可以在静态初始化块中完成。

    【讨论】:

      【解决方案4】:

      static 表示该变量在应用程序中是唯一的。 final 表示只能设置一次。

      如果在构造函数中设置它,则允许多次设置变量。

      因此你应该直接初始化它或提出一个静态方法来初始化它。

      【讨论】:

        【解决方案5】:

        考虑一下。你可以用你的代码做到这一点:

        A a = new A();
        A b = new A(); // Wrong... x is already initialised
        

        初始化x的正确方法是:

        public class A 
        {    
            private static final int x = 5;
        }
        

        public class A 
        {    
            private static final int x;
        
            static
            {
                x = 5;
            }
        }
        

        【讨论】:

          【解决方案6】:

          Final 并不意味着必须在构造函数中初始化。 通常这是这样做的:

           private static final int x = 5;
          

          static 表示该变量将通过类的多个实例共享。例如:

          public class Car {
             static String name;
             public Car(String name) {
                this.name = name;
             }
          }
          
          ...
          
          Car a = new Car("Volkswagen");
          System.out.println(a.name); // Produces Volkswagen
          
          Car b = new Car("Mercedes");
          System.out.println(b.name); // Produces Mercedes
          System.out.println(a.name); // Produces Mercedes
          

          【讨论】:

            【解决方案7】:

            静态

            关键字static 表示对象的成员(在本例中为字段)不绑定到类的实例,而是类的成员。如果静态成员是字段,则在加载类时初始化。

            它可以通过类而不是通过实例来访问(尽管后者不是不可能的,它被认为是错误的形式),所以它可以在构造函数根本没有运行的情况下访问——永远。

            决赛

            关键字final,当应用于对象的字段时,意味着它只能被分配一次,并且在初始化期间必须被分配。

            静态决赛

            综合起来,这两个关键字有效地定义了一个常量:它只能被分配一次,必须被分配,并且对于该类的所有实例都是相同的。

            由于静态字段是在类加载期间初始化的,因此必须在声明时或在静态初始化程序块中对其进行初始化。

            这意味着当你到达构造函数时,它已经被初始化了,因为它需要已经被初始化了。

            单例

            如果您正在寻找只分配一次但多次阅读的班级成员,那么您正在与a singleton 打交道。单例模式通常用于访问共享资源。

            该字段是静态的,但不是最终的;相反,当访问该字段时,代码会检查它是否已经被初始化,如果没有,它就会在那里完成。请注意,在多线程环境中,您需要同步对字段的访问,以避免在初始化时访问它。

            【讨论】:

              【解决方案8】:
                  public class StaticFinalExample {
                /*
                 * Static final fields should be initialized either in
                 * static blocks or at the time of declaration only
                 * Reason : They variables are like the utility fields which should be accessible
                 * before object creation only once.
                 */
                static final int x;
              
                /*
                 * Final variables shuould be initialized either at the time of declaration or
                 * in initialization block or constructor only as they are not accessible in static block
                 */
                final int y;
              
                /*
                 * Static variables can be initialized either at the time of declaration or
                 * in initialization or constructor or static block. Since the default value is given to the
                 * static variables by compiler, so it depends on when you need the value
                 * depending on that you can initialize the variable appropriately
                 * An example of this is shown below in the main method
                 */
                static int z;
              
                static {
                  x = 20; // Correct
                }
                {
                  y = 40; // Correct
                }
                StaticFinalExample() {
                  z = 50; // Correct
                }
                public static void main (String args[]) {
                  System.out.println("Before Initialization in Constructor" + z);   // It will print 0
                  System.out.println("After Initializtion in Constructor" + new StaticFinalExample().z); // It will print 50
                }
              }
              

              【讨论】:

                猜你喜欢
                • 2011-02-15
                • 2013-01-03
                • 2014-10-06
                • 2019-11-13
                • 1970-01-01
                • 2011-07-02
                • 2014-08-23
                • 1970-01-01
                • 2012-01-07
                相关资源
                最近更新 更多