在构造函数中直接赋值final变量和赋值final变量有区别吗?



最终变量value的这两种初始化是否有区别?

class Test {
    final int value = 7;
    Test() {}
}

class Test {
    final int value;
    Test() {
        value = 7;
    }
}

,

EDIT:一个更复杂的例子,涉及子类。在这种情况下,"0"被打印到标准输出,但如果我直接赋值,则打印7。

import javax.swing.*;
import java.beans.PropertyChangeListener;
class TestBox extends JCheckBox {
    final int value;
    public TestBox() {
        value = 7;
    }
    public void addPropertyChangeListener(PropertyChangeListener l) {
        System.out.println(value);
        super.addPropertyChangeListener(l); 
    }
    public static void main(String... args) {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        frame.setContentPane(panel);
        panel.add(new TestBox());
        frame.pack();
        frame.setVisible(true);
    }
}

字节码级别不同:

源代码:

  final int value;
  public TestBox() {
      value = 7;
  }

addPropertyChangeListener生成以下代码:

   0:   getstatic       #3; 
   3:   aload_0
   4:   getfield        #2; 
   7:   invokevirtual   #4; 

和源代码:

final int value = 7;
public TestBox() {      
}

addPropertyChangeListener生成以下代码:

   0:   getstatic       #3; 
   3:   bipush  7
   5:   invokevirtual   #4; 

所以差别很小。但不实际。

如果在定义语句中初始化,编译器似乎可以将final变量作为常量处理。当然不同的编译器会有不同的处理方式

尝试了一个非常简单的例子,是的,当value在父类的构造函数中被访问时,它被初始化(应该是),除非它是final 在声明时初始化。该过程与ejb描述的过程相同,但有一个#0步骤:如果有,则使用指定的值初始化final。

对final变量的一个常见误解是它不能改变它的值。final修饰符(JLS 4.5.4)的实际含义是"一个final变量只能被赋值一次"。

您遇到了这样一种情况,即可能对所谓的"blank final"(已声明,但尚未赋值)变量求值,以便它对指定的数据类型求值为默认值,即使稍后为其赋了不同的值。

除此之外,在第二种情况下,您可以根据调用构造函数或传递给它的参数分配不同的值,NO。

不,没有。唯一的区别是初始化字段的顺序:直接初始化的字段在构造函数中初始化的字段之前初始化。

我不认为有什么区别。但是你需要的值可能会帮助你决定使用哪个。

    如果变量是final的,并且在构造函数中被赋了固定值,那么不需要在构造函数中赋值。
  1. 如果变量是final的,并且作为参数在构造函数中分配了不同的值,那么你需要在构造函数中分配它。

通常使用第一种情况。因为据我所知,final变量就是常量

构造函数按以下顺序执行:

  1. super()被调用。
  2. 初始化局部变量,调用匿名初始化块{}。
  3. 调用构造函数本身的代码。请注意,如果构造函数显式调用super()本身,则在#1中进行处理。

所以你的问题的答案是,初始化将从带初始化声明版本的#2移动到构造函数中初始化版本的#3。但是,除非您有匿名初始化块{}或可能使用其他字段的先前初始化来初始化的字段,否则无法区分它们。

最新更新