Java中静态块的必要性

Java中静态块的必要性,java,static,initialization,Java,Static,Initialization,我发现在Java中,有一个称为静态块的特性,它包括第一次加载类时执行的代码(我不明白“加载”是什么意思,它是指初始化吗?)。是否有任何理由在静态块中而不是在构造函数中执行初始化位?我的意思是,即使构造函数也会做同样的事情,在初始化类时做所有必要的事情。静态块是否完成了构造函数无法完成的任何事情?你不能用构造函数初始化静态变量——或者至少你可能不应该这样做,它也不会特别有用 特别是当您试图初始化需要生成重要逻辑的静态常量时,这应该发生在静态块中,而不是构造函数中。加载类时,静态初始值设定项会运行,

我发现在Java中,有一个称为
静态块的特性,它包括第一次加载类时执行的代码(我不明白“加载”是什么意思,它是指初始化吗?)。是否有任何理由在静态块中而不是在构造函数中执行初始化位?我的意思是,即使构造函数也会做同样的事情,在初始化类时做所有必要的事情。静态块是否完成了构造函数无法完成的任何事情?

你不能用构造函数初始化静态变量——或者至少你可能不应该这样做,它也不会特别有用


特别是当您试图初始化需要生成重要逻辑的静态常量时,这应该发生在静态块中,而不是构造函数中。

加载类时,静态初始值设定项会运行,即使您从未创建任何该类型的对象

  • 并非所有类都要实例化。构造函数可能永远不会被调用。它甚至可能是私人的
  • 在运行构造函数之前,您可能希望访问类的静态字段
  • 加载类时,静态初始值设定项仅运行一次。将为实例化的该类型的每个对象调用构造函数

    • 它们是两个独立的东西。使用构造函数初始化类的一个实例时,静态初始化块在加载该类时初始化静态成员。

      在创建该类实例时调用构造函数

      静态块是在类加载器加载此类定义时调用的,因此我们可以初始化此类的静态成员。
      我们不应该从构造函数初始化静态成员,因为它们是类定义而不是对象的一部分

      静态块在您必须执行某些操作时非常有用,即使没有创建实例。例如,用于初始化具有非静态值的静态变量。

      静态块的作用与构造函数不同。基本上有两个不同的概念

      静态块在类加载到内存时初始化,这意味着JVM读取u'r字节码时。 初始化可以是任何东西,可以是变量初始化,也可以是该类的所有对象都应该共享的任何东西


      然而,构造函数仅为该对象初始化变量。

      我首先要强调您问题中的一点:

      构造函数也做同样的事情,在初始化类时做所有必要的事情

      这是不正确的。构造函数在创建类的实例时执行所有必要的初始化。当类本身第一次加载到内存并初始化时,没有构造函数执行(除非类的实例恰好作为类初始化的一部分创建)。这种混淆(初始化类和初始化类实例之间的混淆)可能就是您质疑
      静态
      块的实用性的原因

      如果类具有需要复杂初始化的静态成员,则可以使用
      static
      块。假设您需要某种静态映射(此处的目的无关)。您可以像这样在线声明它:

      public static final Map<String, String> initials = new HashMap<String, String>();
      
      如果您想更具保护性,可以这样做:

      public static final Map<String, String> initials;
      static {
          Map<String, String> map = new HashMap<String, String>()
          map.put("AEN", "Alfred E. Newman");
          // etc.
          initials = Collections.unmodifiableMap(map);
      }
      
      但是,请注意,这并不是像您建议的那样,用构造函数中的代码替换
      静态
      块!此外,如果您需要以相互关联的方式初始化多个
      静态
      字段,则这将不起作用

      一个
      静态
      块很难替换的情况是一个“主”类,它需要初始化几个其他类一次

      public class Master {
          static {
              SlaveClass1.init();
              SlaveClass2.init(SlaveClass1.someInitializedValue);
              // etc.
          }
      }
      
      特别是如果您不想将任何依赖硬连接到
      SlaveClass2
      上的
      SlaveClass1
      ,则需要类似这样的主代码。这种东西绝对不属于构造函数

      请注意,还有一种称为实例初始值设定项块的东西。它是在创建每个实例时运行的匿名代码块。(语法就像一个
      static
      块,但是没有
      static
      关键字。)它对于匿名类特别有用,因为它们不能有命名构造函数。下面是一个真实的例子。由于(不可思议地)
      GZIPOutputStream
      没有构造函数或任何api调用,您可以使用它们指定压缩级别,并且默认压缩级别为none,因此您需要子类化
      GZIPOutputStream
      ,以获得任何压缩。您始终可以编写显式子类,但编写匿名类更方便:

      OutputStream os = . . .;
      OutputStream gzos = new GZIPOutputStream(os) {
          {
              // def is an inherited, protected field that does the actual compression
              def = new Deflator(9, true); // maximum compression, no ZLIB header
          }
      };
      

      当您想要初始化静态字段时,静态块非常有用

      如果我们初始化一个类,静态初始化器将运行,这并不要求我们实例化一个类。但构造函数只有在我们创建类的实例时才运行

      例如:

      class MyClass
      {   
          static
          {
              System.out.println("I am static initializer");
          }
          MyClass()
          {
              System.out.println("I am constructor");
          }
      
          static void staticMethod()
          {
              System.out.println("I am static method");
          }
      }
      
      如果我们运行:

      MyClass.staticMethod();
      
      输出:

      I am static initializer
      I am static method
      
      I am static initializer
      I am constructor
      
      我们从未创建过实例,因此不会调用构造函数,但会调用静态初始值设定项

      如果我们创建一个类的实例,静态initilizer和构造函数都会运行。没有意外

      MyClass x = new MyClass();
      
      输出:

      I am static initializer
      I am static method
      
      I am static initializer
      I am constructor
      
      请注意,如果我们运行:

      MyClass x;
      
      输出:(空)


      声明变量
      x
      不需要初始化
      MyClass
      ,因此静态初始值设定项不会运行。

      当您必须执行某些操作时,即使没有创建实例,静态块对构造函数也很有用。例如,使用非静态值初始化静态变量。

      理解静态块的一种方法是; 它充当构造函数。然而,两者之间的区别是 静态块实例化类或静态变量,而构造函数用于实例化对象变量

      考虑下面的类

      public class Part{
      
        String name;
        static String producer;
      
        public Part(String name){
            this.name = name;
        }
      
        static {
          producer = "Boeing";
        }
      
      }
      
      从该类创建的对象将
      Part engine = new Part("JetEngine");
      Part Wheel = new Part("JetWheel");