简体   繁体   English

直接分配最终变量和在构造函数中分配最终变量之间有区别吗?

[英]Is there a difference between directly assigning a final variable and assigning a final variable in the constructor?

is there a difference between these two initializations of the final variable value ? 这两个最终变量value初始化之间有区别吗?

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

and

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

-- -

EDIT: A more complex example, involving subclasses. 编辑:一个更复杂的例子,涉及子类。 "0" is printed to stdout in this case, but 7 is printed if i assign the value directly. 在这种情况下,“0”打印到stdout,但如果直接指定值,则打印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);
    }
}

There is differece in byte-code level: 字节码级别有差异:

Source code: 源代码:

  final int value;

  public TestBox() {
      value = 7;
  }

Produces following code from addPropertyChangeListener : addPropertyChangeListener生成以下代码:

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

And source code: 和源代码:

final int value = 7;

public TestBox() {      
}

Produces the following code from addPropertyChangeListener : addPropertyChangeListener生成以下代码:

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

So there is a small difference. 所以有一点不同。 But not practical. 但不实用。

Seems that compiler can handle a final variable as a constant if it is intialized in definition statement. 似乎编译器可以将最终变量作为常量处理,如果它在定义语句中初始化的话。 Of course different compilers may do it different way. 当然,不同的编译器可能会采用不同的方式。

Tried with a very simple example and yes, when value is accessed in the parent's constructor it is unitialized (as it should be), unless it's final and initialized when declared. 尝试了一个非常简单的例子,是的,当在父的构造函数中访问值时,它是单元化的(应该是), 除非它是最终的在声明时初始化。 The process is that described by EJP, but with a #0 step: finals are initialized with the specified value, if any. 该过程由EJP描述,但是使用#0步骤:使用指定值(如果有)初始化终结。

A common misinterpretation of a final variable is that it can't change its value. 对最终变量的常见误解是它无法改变其值。 The actual meaning of the final modifier (JLS 4.5.4) is that "a final variable may only be assigned to once". 最终修饰符(JLS 4.5.4)的实际含义是“最终变量只能分配给一次”。

You've run into one of the situations where it is possible to evaluate a so called "blank final" (declared, but not yet assigned) variable, so that it evaluates to the default value for the specified datatype, even if its later assigned a different value. 您已经遇到可以评估所谓的“空白最终”(已声明但尚未分配)变量的情况之一,以便它评估指定数据类型的默认值,即使后来已分配不同的价值。

其他在第二种情况下,您可以根据调用的构造函数或传递给它的参数指定不同的值, NO。

No, there is not. 不,那里没有。 The only difference is the order used to initialize the fields: fields initialized directly are initialized before the ones initialized in the constructor. 唯一的区别是用于初始化字段的顺序:直接初始化的字段在构造函数中初始化的字段之前初始化。

I don't think there are any difference. 我认为没有任何区别。 But the value you need in it might help you in decide which to use. 但是你需要它的价值可能会帮助你决定使用哪个。

  1. If the variable is final and assigned with fixed value in constructor then no need to assign it in constructor. 如果变量是final并且在构造函数中赋值为固定值,则无需在构造函数中赋值。
  2. If the variable is final and assigned with different values, passed as argument, in constructor then you need to assign it in constructor. 如果变量是final并且在构造函数中分配了不同的值(作为参数传递),那么您需要在构造函数中分配它。

Mostly the first case is used. 大多数情况下使用第一种情况。 Because as far as I know final varibales are nothing but the constants. 因为据我所知,最终的变量只是常量。

A constructor executes in the following order: 构造函数按以下顺序执行:

  1. super() is called. 调用super()。
  2. Local variables are initialized and anonymous initializer blocks {} are called. 初始化局部变量并调用匿名初始化块{}。
  3. The code in the constructor itself is called. 构造函数本身的代码被调用。 Note that if the constructor explicitly calls super() itself this is taken care of under #1. 请注意,如果构造函数显式调用super()本身,则在#1下进行处理。

So the answer to your question is that the initialization would be moved from #2 in the declaration-with-initializer version to #3 in the initialize-in-constructor version. 因此,您的问题的答案是初始化将从initial-in-initializer版本中的#2移动到initialize-in-constructor版本中的#3。 However unless you have anonymous initializer blocks {} or possibly fields that are initialized using prior initializations of other fields, it would be impossible to tell the difference. 但是,除非您有匿名初始化程序块{}或可能使用其他字段的先前初始化初始化的字段,否则无法区分它们。

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

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