What is the difference between a static and a non-static initialization code block
我的问题是关于静态关键字的一个特殊用法。可以使用
1 2 3 4 5 6 7 8 9 10 | public class Test { private static final int a; static { a = 5; doSomething(a); } private static int doSomething(int x) { return (x+5); } } |
如果删除
在这两方面我都很困惑。我应该如何拥有不属于任何方法的代码部分?如何调用它?一般来说,这个用法的目的是什么?或者更好,我在哪里可以找到关于这个的文档?
带有静态修饰符的代码块表示类初始值设定项;没有静态修饰符的代码块是实例初始值设定项。
类初始值设定项在加载类时(实际上,当它被解析时,但这是技术性的),按照定义的顺序执行(自上而下,就像简单变量初始值设定项)。
实例初始值设定项是按照类实例化时定义的顺序执行的,紧接着在构造函数代码执行之前,紧接着在超级构造函数调用之后。
如果从
如果还从初始值设定项块中删除
乌夫!什么是静态初始值设定项?
静态初始化器是Java类中的EDOCX1×5代码块,在调用构造函数或主方法之前只运行一次。
好啊!告诉我更多…
- 是任何Java类中的代码块EDOCX1 6。并在调用类时由虚拟机执行。
- 不支持
return 语句。 - 不支持任何参数。
- 不支持
this 或super 。
嗯,我在哪里可以用呢?
可以在任何你觉得合适的地方使用:)很简单。但我看到,在进行数据库连接、API初始化、日志记录等操作时,大多数时候都会用到它。
别光叫!例子在哪里?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package com.example.learnjava; import java.util.ArrayList; public class Fruit { static { System.out.println("Inside Static Initializer."); // fruits array ArrayList<String> fruits = new ArrayList<>(); fruits.add("Apple"); fruits.add("Orange"); fruits.add("Pear"); // print fruits for (String fruit : fruits) { System.out.println(fruit); } System.out.println("End Static Initializer. "); } public static void main(String[] args) { System.out.println("Inside Main Method."); } } |
输出????
Inside Static Initializer.
Apple
Orange
Pear
End Static Initializer.
Inside Main Method.
希望这有帮助!
它在加载类时自动调用,并且没有其他方法来调用它(甚至没有通过反射)。
我个人只在编写JNI代码时使用过它:
1 2 3 4 5 |
这直接来自http://www.programcreek.com/2011/10/java-class-instance-initials/
1。执行顺序看看下面的类,你知道先执行哪个类吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class Foo { //instance variable initializer String s ="abc"; //constructor public Foo() { System.out.println("constructor called"); } //static initializer static { System.out.println("static initializer called"); } //instance initializer { System.out.println("instance initializer called"); } public static void main(String[] args) { new Foo(); new Foo(); } } |
输出:
static initializer called
instance initializer called
constructor called
instance initializer called
constructor called
2。Java实例初始化器是如何工作的?
上面的实例初始值设定项包含println语句。为了理解它是如何工作的,我们可以把它当作一个变量赋值语句来处理,例如,
而不是
你可以写
1 2 | int b; b = 0; |
因此,实例初始值设定项和实例变量初始值设定项基本相同。
三。实例初始值设定项何时有用?很少使用实例初始值设定项,但在以下情况下,它仍然是实例变量初始值设定项的有用替代方法:
当然,这样的代码可以用构造函数编写。但是,如果一个类有多个构造函数,则必须在每个构造函数中重复代码。
使用实例初始值设定项,只需编写一次代码,无论使用什么构造函数创建对象,都将执行该代码。(我想这只是一个概念,不经常使用。)
实例初始值设定项很有用的另一种情况是匿名内部类,它根本不能声明任何构造函数。(这是放置日志功能的好地方吗?)
多亏了德海因。
还要注意,实现接口[1]的匿名类没有构造函数。因此,在构造时需要实例初始值设定项来执行任何类型的表达式。
"final"保证变量必须在对象初始值设定项代码结束之前初始化。同样,"static final"保证变量将在类初始化代码结束时初始化。从初始化代码中省略"static"会将其转换为对象初始化代码;因此,变量不再满足其保证。
当开发人员使用初始化程序块时,Java编译器将初始化器复制到当前类的每个构造函数中。
例子:
以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | class MyClass { private int myField = 3; { myField = myField + 2; //myField is worth 5 for all instance } public MyClass() { myField = myField * 4; //myField is worth 20 for all instance initialized with this construtor } public MyClass(int _myParam) { if (_myParam > 0) { myField = myField * 4; //myField is worth 20 for all instance initialized with this construtor //if _myParam is greater than 0 } else { myField = myField + 5; //myField is worth 10 for all instance initialized with this construtor //if _myParam is lower than 0 or if _myParam is worth 0 } } public void setMyField(int _myField) { myField = _myField; } public int getMyField() { return myField; } } public class MainClass{ public static void main(String[] args) { MyClass myFirstInstance_ = new MyClass(); System.out.println(myFirstInstance_.getMyField());//20 MyClass mySecondInstance_ = new MyClass(1); System.out.println(mySecondInstance_.getMyField());//20 MyClass myThirdInstance_ = new MyClass(-1); System.out.println(myThirdInstance_.getMyField());//10 } } |
相当于:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | class MyClass { private int myField = 3; public MyClass() { myField = myField + 2; myField = myField * 4; //myField is worth 20 for all instance initialized with this construtor } public MyClass(int _myParam) { myField = myField + 2; if (_myParam > 0) { myField = myField * 4; //myField is worth 20 for all instance initialized with this construtor //if _myParam is greater than 0 } else { myField = myField + 5; //myField is worth 10 for all instance initialized with this construtor //if _myParam is lower than 0 or if _myParam is worth 0 } } public void setMyField(int _myField) { myField = _myField; } public int getMyField() { return myField; } } public class MainClass{ public static void main(String[] args) { MyClass myFirstInstance_ = new MyClass(); System.out.println(myFirstInstance_.getMyField());//20 MyClass mySecondInstance_ = new MyClass(1); System.out.println(mySecondInstance_.getMyField());//20 MyClass myThirdInstance_ = new MyClass(-1); System.out.println(myThirdInstance_.getMyField());//10 } } |
我希望开发人员能够理解我的示例。
您不会将代码写入需要在程序中任何位置调用的静态块中。如果要调用代码的目的,则必须将其放在方法中。
可以编写静态初始值设定项块,以便在加载类时初始化静态变量,但此代码可能更复杂。
静态初始值设定项块看起来像一个没有名称、没有参数和没有返回类型的方法。因为你从不叫它,它不需要名字。唯一一次调用它是在虚拟机加载类时。
静态代码块可用于实例化或初始化类变量(而不是对象变量)。因此,声明"a"静态意味着只有一个由所有测试对象共享,并且静态代码块在第一次加载测试类时仅初始化"a",不管创建了多少个测试对象。