What's the proper way or underlying difference of initializing a static variable in one way or another in Java language?

huangapple go评论82阅读模式
英文:

What's the proper way or underlying difference of initializing a static variable in one way or another in Java language?

问题

我对初始化静态变量的适当方式有些怀疑。

我已经意识到我可以直接在定义时为static变量赋值,就像这样:

public class MyClass {
  // 直接初始化
  public static int counter = 0;

此外,我还看到可以使用static块,就像这样:

public class MyClass {
  public static int counter;

  static {
    counter = 0;
  }
}

甚至,我惊讶地发现您还可以从类构造函数中访问static变量,并在那里为它们赋值,就像这样:

public class MyClass {
  public static int counter;

  public MyClass() {
    this.counter = 0;
  }

  public MyClass(int a) {
    this.counter = a;
  }
}

我的问题是:在处理静态变量时,使用一种初始化方式还是另一种初始化方式之间的适当方式或潜在区别是什么?

我还编写并执行了以下代码,以便了解在程序执行过程中变量的修改方式。

public class StaticVariable {
	static int a = 0;

	public StaticVariable(int b) {
		// 构造函数参数b被忽略
		System.out.println("[Inside 1-parameter constructor] Current value of \"a\": " + a + " .");
		System.out.println("[Inside 1-parameter constructor] Value of \"a\" was increased in one ...");
		a++;
	}

	public StaticVariable() {
		System.out.println("[Inside parameterless constructor] Current value of \"a\": " + a + " .");
		System.out.println("[Inside parameterless constructor] Value of \"a\" was increased in one ...");
		a++;
	}

	static {
		System.out.println("[Inside static block] Initial value of \"a\": " + a + " .");	
		System.out.println("[Inside static block] Value of \"a\" was increased in one ...");
		a++;
	}

	public static void main(String[] args) {
		System.out.println("[main method] Current value of \"a\": " + StaticVariable.a + " .");
		StaticVariable object = new StaticVariable();
		System.out.println("[main method] Current value of \"a\": " + StaticVariable.a + " .");
		StaticVariable object2 = new StaticVariable(10);
		System.out.println("[main method] Current value of \"a\": " + StaticVariable.a);
		System.out.println("[main method] Directly setting value of \"a\" with 560");
		StaticVariable.a = 560;
		System.out.println("Updated value of \"a\": " + StaticVariable.a);
	}
}
英文:

I am a little bit doubtful about the proper way of initializing static variables.

I've realized that I can directly assign a value to a static variable at the definition time, like in:

public class MyClass {
  // Direct initialization
  public static int counter = 0;

Also, I have seen that you can use a static block, like in:

public class MyClass {
  public static int counter;

  static {
    counter = 0;
  }
}

Even, I have surprisingly seen that you can also access static variables from class constructors and set them a value from there, like in:

public class MyClass {
  public static int counter;

  public MyClass() {
    this.counter = 0;
  }

  public MyClass( int a ) {
    this.counter = a;
  }
}

My question is: What's the proper way or underlying difference among using one or another type of initialization when dealing with static variables?

I have also wrote and executed the following code, so I could realize how the variable is being modified along the program execution.

public class StaticVariable {
	static int a = 0;

	public StaticVariable( int b ) {
		// The constructor parameter b is ignored
		System.out.println( "[Inside 1-parameter constructor] Current value of \"a\": " + a + " ." );
		System.out.println( "[Inside 1-parameter constructor] Value of \"a\" was increased in one ..." );
	  a++;
	}

	public StaticVariable() {
		System.out.println( "[Inside parameterless constructor] Current value of \"a\": " + a + " ." );
		System.out.println( "[Inside parameterless constructor] Value of \"a\" was increased in one ..." );
	  a++;
	}

	static {
		System.out.println( "[Inside static block] Initial value of \"a\": " + a + " ." );	
		System.out.println( "[Inside static block] Value of \"a\" was increased in one ..." );
	  a++;
	}

	public static void main( String[] args ) {
		System.out.println( "[main method] Current value of \"a\": " + StaticVariable.a + " ." );
		StaticVariable object = new StaticVariable();
		System.out.println( "[main method] Current value of \"a\": " + StaticVariable.a + " ." );
		StaticVariable object2 = new StaticVariable( 10 );
		System.out.println( "[main method] Current value of \"a\": " + StaticVariable.a );
		System.out.println( "[main method] Directly setting value of \"a\" with 560" );
		StaticVariable.a = 560;
		System.out.println( "Updated value of \"a\": " + StaticVariable.a );
	}
}

Thanks in advance.

答案1

得分: 2

只在必要时使用static代码块。

在你的前两个示例中,没有语义或性能差异,编写代码的正确方法是简单的方式。

第三个示例在语义上是不同的。设置器实际上并没有初始化静态变量,它是在重新初始化该变量。(你可以在调用设置器之前调用获取器,这会显示真正的初始值;即零。)

使用设置器(如第三个示例)没有任何问题,但它在执行不同的操作。如果你只是想简单地初始化为固定值,不要用这种方式。采用简单的方式。

(最后一个示例似乎与题目无关,所以我会忽略它。)

在某些情况下,可能无法在单个表达式中执行必要的初始化。(例如,可能需要执行一系列语句来填充对象,或捕获和处理异常,或处理相互引用的final对象1。)在这些情况下,static代码块是一种可能的解决方案。


在前两种方法之间是否存在“基本差异”?

我认为没有。

static Foo foo = <expression>;   // 这是合法的 Java 代码

在语义上与:

static Foo foo;
static {
    foo = <expression>;
}

是100%语义等效的。

只是static代码块可以做一些用简单初始化器无法做到的事情。static代码块可以比单一赋值语句更复杂。

1 - 这里的术语使用比较宽泛。实际上是变量是final而不是对象。

英文:

Short answer: only use static blocks if you need to use them.

In your first two examples, there is no semantic or performance difference, and the proper way to write the code is the simple way.

The third example is semantically different. The setter is not actually initializing the static variable. It is re-initializing the variable. (You can call the getter before calling the setter, and that will show you the real initial value; i.e. zero.)

There is nothing wrong with using a setter (as per your third example) but it is doing something different. If you just want a simple initialization to a fixed value, don't do it this way. Do it the simple way.

(The final example doesn't appear to be apropos, so I will ignore it.)

In some cases it is not possible to perform the necessary initialization in a single expression. (For example, it may be necessary to execute a sequence of statements to populate an object, or catch and handle an exception, or deal with final objects<sup>1</sup> that reference each other.) In these cases, a static block is a possible solutions.


Is there an "underlying difference" between the first two approaches?

I don't think so.

static Foo foo = &lt;expression&gt;;   // where this is legal Java code

is 100% semantically equivalent to:

static Foo foo;
static {
foo = &lt;expression&gt;;
}

It is just that there are some things that you can do with a static block that you can't do with a simple initializer. The static block can be more complicated than a single assignment statement.


<sup>1 - I am being "loose" with the terminology here. It is actually the variables that are final not the objects.</sup>

答案2

得分: 2

第一种和第二种方法是等效的。通常情况下,你会发现第一种方法在对单个变量进行简单初始化时更为常见。但有时候,在块中进行静态初始化可以更方便地处理更复杂的情况,例如向一个static变量的集合中添加多个元素,就像这样:

static List<String> list;
static {
  list = new ArrayList<>();
  list.add("hello");
  list.add("world");
}

至于你描述的第三种选项,在实例化过程中进行初始化,它会在每次创建类的新实例时重新初始化静态变量。最好还是避免这样做。我想不出会希望出现这种情况的场景。

英文:

The first and second approaches are equivalent. Typically you will find the first approach to be much more common for simple initializations of a single variable. But sometimes static initialization in a block can be convenient for more complicated situations, for example, adding several elements to a collection which is a static variable, as in:

static List&lt;String&gt; list;
static {
list = new ArrayList&lt;&gt;();
list.add(&quot;hello&quot;);
list.add(&quot;world&quot;);
}

As for the third option you describe, initializing during instantiation, it will reinitialize the static variable each time a new instance of the class is created. Probably best to avoid this. I can't think of a situation where I would have wanted that.

答案3

得分: 1

静态字段属于类,而不属于对象,因此在构造函数中设置它们的值并不是一个好主意,因为每次创建对象时都可能影响代码的其他部分。

在直接设置和在静态块中设置之间,我个人更喜欢直接设置,因为这样更清晰,其他用户可以更容易读懂。

英文:

Static fields belong to class not the objects, so it is not such a good idea to set their value in constructors. so that every time an object is created it might affect the other parts of your code.

among setting directly or in the static block, I personally prefer direct one because of it is more clear and readable by other users.

huangapple
  • 本文由 发表于 2020年5月4日 12:05:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/61585003.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定