【问题标题】:Difference between two class member declaration and initialization两个类成员声明和初始化的区别
【发布时间】:2014-08-19 08:29:02
【问题描述】:

以下几种类成员声明和初始化的确切区别是什么?

选项 1:

public class MyClass {
    private int myInt = 1;
}

选项 2:

public class MyClass {
    private int myInt;
    {
        myInt = 1;
    }
}

【问题讨论】:

  • 不尊重............
  • 如果变量是final会有所不同。
  • @Holger 你能告诉我你的意思吗?会有什么不同?
  • @d3rbastl3r: I added an answer

标签: java initialization declaration class-members


【解决方案1】:

如果是

public class MyClass {
    private int myInt;
    {
        myInt = 1;
    }
}

实例初始化块在构造函数之前运行每次你构造一个对象。

在第二种情况下,它是相同的:)

结论:没有区别(但值得知道构造对象时会发生什么)。

docs - Initializing Instance Members

Java 编译器将初始化程序块复制到每个构造函数中。 因此,这种方法可以用于在之间共享一个代码块 多个构造函数。

请注意,您可以使用 javap -c 反编译 class 文件并进行验证。

【讨论】:

    【解决方案2】:

    区别在于语法。在大多数情况下,第一种形式更具可读性且易于使用。第二种形式可能更强大,因为它将声明和初始化分开,但给出这个确切的例子,编译器将生成完全相同的字节码。这是因为编译器会将字段初始化器和 init 块放入每个构造函数中。在更复杂的情况下,您会发现两种方法之间的顺序可能会有所不同;这是一个最好避免的微妙区域,因为它可能会导致意外的 NullPointerExceptions。

    为了说服自己,可以使用 javap -c 反编译生成的类文件。

    对于我们得到的第一个版本

    public class A {
      public A();
        Code:
           0: aload_0       
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: aload_0       
           5: iconst_1      
           6: putfield      #2                  // Field myInt:I
           9: return        
    }
    

    我们得到第二个版本

    public class B {
      public B();
        Code:
           0: aload_0       
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: aload_0       
           5: iconst_1      
           6: putfield      #2                  // Field myInt:I
           9: return        
    }
    

    【讨论】:

      【解决方案3】:

      在第一种情况下,您声明并初始化成员 myInt 在第二种情况下,您在两个语句中执行任务。在这种情况下,添加一对大括号并没有真正的区别。

      赋值:丢弃变量的旧值并用新值替换它。喜欢:

      myInt = 8;
      

      初始化:这是一种特殊的赋值:第一个。在初始化之前,对象具有 null 值,原始类型具有默认值,例如 0 或 false。(可以与声明一起完成,就像您在第一种情况下所做的那样),例如:

      private int myInt = 1; //both together
      

      声明:声明说明变量的类型及其名称。一个变量只能声明一次。编译器使用它来帮助程序员避免错误,例如将字符串值分配给整数变量。在读取或分配变量之前,必须先声明该变量。喜欢:

      private int myint;
      

      希望有帮助:)

      【讨论】:

        【解决方案4】:

        如果变量声明为final,它会有所不同。如果 final 变量在声明时立即分配了编译时常量,则该变量也将是编译时常量。这意味着,它的值将在编译时被复制,而不是在运行时在访问变量时读取,并且它可能出现在只允许编译时常量的地方:

        仅作说明:

        public class MyClass {
          private final int myInt = 1;
          private final int myIntPlusOne = myInt + 1;// adding two constants
        
          public MyClass(int parameter) {
            switch(parameter)
            {
              case myInt: // using a name for 1
              case myIntPlusOne: // and for 2
            }
          }
        }
        

        如果您将final int myInt = 1 更改为final int myInt; { myInt = 1; },这将不起作用。

        确切的规格在Java Language Specification §4.12.4. final Variables:

        常量变量是原始类型或 String 类型的最终变量,使用常量表达式 (§15.28) 进行初始化。

        对于非final 变量,没有区别。

        【讨论】:

        • @Chris K:这与优化无关,它是影响二进制兼容性的要求。如果您更改此类变量的值而不重新编译所有内联该值的类,您将获得令人惊讶的结果。此外,当通过反射修改此类字段时,大多数使用该变量的代码都不会注意到。
        • @Chris K:我改写了它以避免使用“内联”这个词。
        【解决方案5】:

        没有尊重,但它可以让你的代码更干净。 请记住,

        {
        
        }
        

        与int无关!

        【讨论】:

          猜你喜欢
          • 2015-07-24
          • 1970-01-01
          • 2012-02-26
          • 2012-11-23
          • 2023-03-11
          相关资源
          最近更新 更多