Java 什么是初始化块?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3987428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is an initialization block?
提问by Sumithra
We can put code in a constructor or a method or an initialization block. What is the use of initialization block? Is it necessary that every java program must have it?
我们可以将代码放在构造函数或方法或初始化块中。初始化块有什么用?是不是每个java程序都必须有它?
采纳答案by aioobe
First of all, there are two types of initialization blocks:
首先,有两种类型的初始化块:
- instance initialization blocks, and
- static initialization blocks.
- 实例初始化块,和
- 静态初始化块。
This code should illustrate the use of them and in which order they are executed:
这段代码应该说明它们的使用以及它们的执行顺序:
public class Test {
static int staticVariable;
int nonStaticVariable;
// Static initialization block:
// Runs once (when the class is initialized)
static {
System.out.println("Static initalization.");
staticVariable = 5;
}
// Instance initialization block:
// Runs each time you instantiate an object
{
System.out.println("Instance initialization.");
nonStaticVariable = 7;
}
public Test() {
System.out.println("Constructor.");
}
public static void main(String[] args) {
new Test();
new Test();
}
}
Prints:
印刷:
Static initalization.
Instance initialization.
Constructor.
Instance initialization.
Constructor.
Instance itialization blocks are useful if you want to have some code run regardless of which constructor is used or if you want to do some instance initialization for anonymous classes.
如果您想运行一些代码而不管使用哪个构造函数,或者您想为匿名类进行一些实例初始化,则实例初始化块非常有用。
回答by Gaurav Saxena
Initialization blocks are executed whenever the class is initialized and before constructors are invoked. They are typically placed above the constructors within braces. It is not at all necessary to include them in your classes.
初始化块在类被初始化时和构造函数被调用之前执行。它们通常放置在大括号内的构造函数之上。完全没有必要将它们包含在您的类中。
They are typically used to initialize reference variables. This pagegives a good explanation
它们通常用于初始化引用变量。这个页面给出了很好的解释
回答by Cameron Skinner
The question is not entirely clear, but here's a brief description of ways you can initialise data in an object. Let's suppose you have a class A that holds a list of objects.
这个问题并不完全清楚,但这里简要描述了您可以在对象中初始化数据的方法。假设您有一个包含对象列表的类 A。
1) Put initial values in the field declaration:
1)将初始值放在字段声明中:
class A {
private List<Object> data = new ArrayList<Object>();
}
2) Assign initial values in the constructor:
2)在构造函数中分配初始值:
class A {
private List<Object> data;
public A() {
data = new ArrayList<Object>();
}
}
These both assume that you do not want to pass "data" as a constructor argument.
这些都假设您不想将“数据”作为构造函数参数传递。
Things get a little tricky if you mix overloaded constructors with internal data like above. Consider:
如果将重载的构造函数与上述内部数据混合使用,事情就会变得有点棘手。考虑:
class B {
private List<Object> data;
private String name;
private String userFriendlyName;
public B() {
data = new ArrayList<Object>();
name = "Default name";
userFriendlyName = "Default user friendly name";
}
public B(String name) {
data = new ArrayList<Object>();
this.name = name;
userFriendlyName = name;
}
public B(String name, String userFriendlyName) {
data = new ArrayList<Object>();
this.name = name;
this.userFriendlyName = userFriendlyName;
}
}
Notice that there is a lot of repeated code. You can fix this by making constructors call each other, or you can have a private initialisation method that each constructor calls:
请注意,有很多重复的代码。您可以通过使构造函数相互调用来解决此问题,或者您可以拥有每个构造函数调用的私有初始化方法:
class B {
private List<Object> data;
private String name;
private String userFriendlyName;
public B() {
this("Default name", "Default user friendly name");
}
public B(String name) {
this(name, name);
}
public B(String name, String userFriendlyName) {
data = new ArrayList<Object>();
this.name = name;
this.userFriendlyName = userFriendlyName;
}
}
or
或者
class B {
private List<Object> data;
private String name;
private String userFriendlyName;
public B() {
init("Default name", "Default user friendly name");
}
public B(String name) {
init(name, name);
}
public B(String name, String userFriendlyName) {
init(name, userFriendlyName);
}
private void init(String _name, String _userFriendlyName) {
data = new ArrayList<Object>();
this.name = name;
this.userFriendlyName = userFriendlyName;
}
}
The two are (more or less) equivalent.
两者是(或多或少)等价的。
I hope that gives you some hints on how to initialise data in your objects. I won't talk about static initialisation blocks as that's probably a bit advanced at the moment.
我希望这能给你一些关于如何在你的对象中初始化数据的提示。我不会谈论静态初始化块,因为目前这可能有点先进。
EDIT: I've interpreted your question as "how do I initialise my instance variables", not "how do initialiser blocks work" as initialiser blocks are a relatively advanced concept, and from the tone of the question it seems you're asking about the simpler concept. I could be wrong.
编辑:我已经将您的问题解释为“我如何初始化我的实例变量”,而不是“初始化块如何工作”,因为初始化块是一个相对高级的概念,从问题的语气来看,您似乎在问更简单的概念。我可能是错的。
回答by Biman Tripathy
would like to add to @aioobe's answer
想添加到@aioobe 的答案中
Order of execution:
执行顺序:
static initialization blocks of super classes
static initialization blocks of the class
instance initialization blocks of super classes
constructors of super classes
instance initialization blocks of the class
constructor of the class.
超类的静态初始化块
类的静态初始化块
超类的实例初始化块
超类的构造函数
类的实例初始化块
类的构造函数。
A couple of additional points to keep in mind (point 1 is reiteration of @aioobe's answer):
需要记住的另外几点(第 1 点是重复@aioobe 的回答):
The code in static initialization block will be executed at class load time (and yes, that means only once per class load), before any instances of the class are constructed and before any static methods are called.
The instance initialization block is actually copied by the Java compiler into every constructor the class has. So every time the code in instance initialization block is executed exactlybefore the code in constructor.
静态初始化块中的代码将在类加载时执行(是的,这意味着每个类加载一次),在构造类的任何实例之前和调用任何静态方法之前。
实例初始化块实际上由 Java 编译器复制到类的每个构造函数中。所以每次实例初始化块中的代码都恰好在构造函数中的代码之前执行。
回答by nenito
The sample code, which is approved as an answer here is correct, but I disagree with it. It does not shows what is happening and I'm going to show you a good example to understand how actually the JVM works:
此处被批准为答案的示例代码是正确的,但我不同意。它没有显示正在发生的事情,我将向您展示一个很好的例子来了解 JVM 的实际工作方式:
package test;
class A {
A() {
print();
}
void print() {
System.out.println("A");
}
}
class B extends A {
static int staticVariable2 = 123456;
static int staticVariable;
static
{
System.out.println(staticVariable2);
System.out.println("Static Initialization block");
staticVariable = Math.round(3.5f);
}
int instanceVariable;
{
System.out.println("Initialization block");
instanceVariable = Math.round(3.5f);
staticVariable = Math.round(3.5f);
}
B() {
System.out.println("Constructor");
}
public static void main(String[] args) {
A a = new B();
a.print();
System.out.println("main");
}
void print() {
System.out.println(instanceVariable);
}
static void somethingElse() {
System.out.println("Static method");
}
}
Before to start commenting on the source code, I'll give you a short explanation of static variables of a class:
在开始评论源代码之前,我会给你一个类的静态变量的简短解释:
First thing is that they are called class variables, they belong to the class not to particular instance of the class. All instances of the class share this static(class) variable. Each and every variable has a default value, depending on primitive or reference type. Another thing is when you reassign the static variable in some of the members of the class (initialization blocks, constructors, methods, properties) and doing so you are changing the value of the static variable not for particular instance, you are changing it for all instances. To conclude static part I will say that the static variables of a class are created not when you instantiate for first time the class, they are created when you define your class, they exist in JVM without the need of any instances. Therefor the correct access of static members from external class (class in which they are not defined) is by using the class name following by dot and then the static member, which you want to access (template: <CLASS_NAME>.<STATIC_VARIABLE_NAME>
).
首先,它们被称为类变量,它们属于类而不属于类的特定实例。类的所有实例共享这个静态(类)变量。每个变量都有一个默认值,具体取决于原始类型或引用类型。另一件事是,当您在类的某些成员(初始化块、构造函数、方法、属性)中重新分配静态变量并这样做时,您正在更改静态变量的值,而不是特定实例,您正在更改所有实例。总结静态部分,我会说类的静态变量不是在您第一次实例化类时创建的,而是在您定义类时创建的,它们存在于 JVM 中而不需要任何实例。<CLASS_NAME>.<STATIC_VARIABLE_NAME>
)。
Now let's look at the code above:
现在让我们看看上面的代码:
The entry point is the main method - there are just three lines of code. I want to refer to the example which is currently approved. According to it the first thing which must be printed after printing "Static Initialization block" is "Initialization block" and here is my disagreement, the non-static initialization block is not called before the constructor, it is called before any initializations of the constructors of the class in which the initialization block is defined. The constructor of the class is the first thing involved when you create an object (instance of the class) and then when you enter the constructor the first part called is either implicit (default) super constructor or explicit super constructor or explicit call to another overloaded constructor (but at some point if there is a chain of overloaded constructors, the last one calls a super constructor, implicitly or explicitly).
入口点是主要方法——只有三行代码。我想参考目前批准的例子。根据它,打印“静态初始化块”后必须打印的第一件事是“初始化块”,这是我的不同意见,非静态初始化块不是在构造函数之前调用,而是在构造函数的任何初始化之前调用定义初始化块的类。
There is polymorphic creation of an object, but before to enter the class B and its main method, the JVM initializes all class(static) variables, then goes through the static initialization blocks if any exist and then enters the class B and starts with the execution of the main method. It goes to the constructor of class B then immediately (implicitly) calls constructor of class A, using polymorphism the method(overridden method) called in the body of the constructor of class A is the one which is defined in class B and in this case the variable named instanceVariable is used before reinitialization. After closing the constructor of class B the thread is returned to constructor of class B but it goes first to the non-static initialization block before printing "Constructor". For better understanding debug it with some IDE, I prefer Eclipse.
对象的创建是多态的,但是在进入B类及其main方法之前,JVM初始化所有类(静态)变量,然后如果存在静态初始化块,然后进入B类并开始执行main方法。它转到类 B 的构造函数,然后立即(隐式)调用类 A 的构造函数,使用多态性,在类 A 的构造函数体中调用的方法(重写方法)是在类 B 中定义的方法,在这种情况下在重新初始化之前使用名为 instanceVariable 的变量。关闭类 B 的构造函数后,线程返回到类 B 的构造函数,但它在打印“构造函数”之前首先进入非静态初始化块。为了更好地理解用一些 IDE 调试它,
回答by Gaurav
nice answer by aioobe adding few more points
aioobe 的回答很好,又增加了几分
public class StaticTest extends parent {
static {
System.out.println("inside satic block");
}
StaticTest() {
System.out.println("inside constructor of child");
}
{
System.out.println("inside initialization block");
}
public static void main(String[] args) {
new StaticTest();
new StaticTest();
System.out.println("inside main");
}
}
class parent {
static {
System.out.println("inside parent Static block");
}
{
System.out.println("inside parent initialisation block");
}
parent() {
System.out.println("inside parent constructor");
}
}
this gives
这给
inside parent Static block
inside satic block
inside parent initialisation block
inside parent constructor
inside initialization block
inside constructor of child
inside parent initialisation block
inside parent constructor
inside initialization block
inside constructor of child
inside main
its like stating the obvious but seems a little more clear.
它就像陈述显而易见的,但似乎更清楚一点。
回答by An?l Emre ?z?elik
public class StaticInitializationBlock {
static int staticVariable;
int instanceVariable;
// Static Initialization Block
static {
System.out.println("Static block");
staticVariable = 5;
}
// Instance Initialization Block
{
instanceVariable = 7;
System.out.println("Instance Block");
System.out.println(staticVariable);
System.out.println(instanceVariable);
staticVariable = 10;
}
public StaticInitializationBlock() {
System.out.println("Constructor");
}
public static void main(String[] args) {
new StaticInitializationBlock();
new StaticInitializationBlock();
}
}
Output:
输出:
Static block
Instance Block
5
7
Constructor
Instance Block
10
7
Constructor
回答by roottraveller
Initializer block contains the code that is always executed whenever an instance is created. It is used to declare/initialise the common part of various constructors of a class.
初始化程序块包含在创建实例时始终执行的代码。它用于声明/初始化类的各种构造函数的公共部分。
The order of initialization constructors and initializer block doesn't matter, initializer block is always executed before constructor.
初始化构造函数和初始化块的顺序无关紧要,初始化块总是在构造函数之前执行。
What if we want to execute some code once for all objects of a class?
如果我们想对一个类的所有对象执行一次代码怎么办?
We use Static Block in Java.
我们在 Java 中使用静态块。
回答by Bhanu Hoysala
Just to add to the excellent answers from @aioobeand @Biman Tripathy.
只是为了补充@aioobe和@Biman Tripathy的优秀答案。
A static initializeris the equivalent of a constructor in the static context. which is needed to setup the static environment. A instance initializeris best for anonymous inner classes.
一个静态初始化是在静态情况下构造的等价物。这是设置静态环境所必需的。一个实例初始化是最好的匿名内部类。
- It is also possible to have multiple initializer blocks in class
- When we have multiple initializer blocks they are executed (actually copied to constructors by JVM) in the order they appear
- Order of initializer blocks matters, but order of initializer blocks mixed with Constructors doesn't
- Abstract classes can also have both static and instance initializer blocks.
- 类中也可以有多个初始化块
- 当我们有多个初始化块时,它们会按照它们出现的顺序执行(实际上是由 JVM 复制到构造函数中)
- 初始化块的顺序很重要,但与构造函数混合的初始化块的顺序并不重要
- 抽象类也可以同时具有静态和实例初始化块。
Code Demo -
代码演示 -
abstract class Aircraft {
protected Integer seatCapacity;
{ // Initial block 1, Before Constructor
System.out.println("Executing: Initial Block 1");
}
Aircraft() {
System.out.println("Executing: Aircraft constructor");
}
{ // Initial block 2, After Constructor
System.out.println("Executing: Initial Block 2");
}
}
class SupersonicAircraft extends Aircraft {
{ // Initial block 3, Internalizing a instance variable
seatCapacity = 300;
System.out.println("Executing: Initial Block 3");
}
{ // Initial block 4
System.out.println("Executing: Initial Block 4");
}
SupersonicAircraft() {
System.out.println("Executing: SupersonicAircraft constructor");
}
}
An instance creation of SupersonicAircraft
will produce logs in below order
的实例创建SupersonicAircraft
将按以下顺序生成日志
Executing: Initial Block 1
Executing: Initial Block 2
Executing: Aircraft constructor
Executing: Initial Block 3
Executing: Initial Block 4
Executing: SupersonicAircraft constructor
Seat Capacity - 300