Recursive class initialization in Java
来源:互联网 发布:linux查看用户和组 编辑:程序博客网 时间:2024/06/05 20:06
when a Java class is referenced and initialized, it has to go through the loading and linking first. Once the loading and linking complete successfully. The class will be initialized. The static variables and constant variables will be initialized during this process. Once the class is initialized, it is ready for use.
If when class A is initialized and it is referencing a class B, the class B will also get initialized. But what will happen if class B is referencing class A as well? This is called recursive class initialization. Will there be a deadlock if this case happens? No, JVM will take care of this situation for you. In this post, we will discuss the recursive class initialization in Java.
For each class or interface C, there is a unique initialization lock LC for C. According to JLS 8.0 section 12.4.2, a class or interface C initialization involves below steps:
1. Synchronize on the initialization lock, LC, for C. This involves waiting until the current thread can acquire LC.
2. If the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this step.
3. If the Class object for C indicates that initialization is in progress for C by the current thread, then this must be a recursive request for initialization. Release LC and complete normally.
There are also some other steps involved, but they are quite self-explained. Here we focus on the step 3 which is most difficult for developers to understand. Below we will use an example to demonstrate step 3.
Here we define three classes StaticFinalTest1, StaticFinalTest2 and Test. Test is the main entry of the program.
StaticFinalTest1.java
public
class
StaticFinalTest1 {
static
final
String[] staticFinal;
static
final
boolean
mode;
static
{
staticFinal = StaticFinalTest2.TLS_v11;
//Reference to StaticFinal2
System.out.println(
"StaticFinalTest1 : staticFinal = "
+StaticFinalTest2.TLS_v11);
mode =
true
;
}
public
static
String[] getStaticFinal(){
return
staticFinal;
}
public
static
boolean
isMode(){
return
mode;
}
}
StaticFinalTest2.java
public
class
StaticFinalTest2 {
static
final
StaticFinalTest2 NONE =
new
StaticFinalTest2(-
1
,
"NONE"
);
static
{
System.out.println(
"StaticFinalTest2 : NONE = "
+NONE);
}
static
final
boolean
isMode = StaticFinalTest1.isMode() ?
true
:
false
;
static
{
System.out.println(
"StaticFinalTest2 : isMode = "
+isMode);
}
static
final
String[] TLS_v11 = {
"TLSv1.1"
};
static
{
System.out.println(
"StaticFinalTest2 : TLS_v11 = "
+TLS_v11);
}
public
final
int
v;
final
String name;
private
StaticFinalTest2(
int
v, String name) {
this
.v = v;
this
.name = name;
System.out.println(
"StaticFinalTest2 : CONSTRUCTOR"
);
}
}
Test.java
public
class
Test {
public
static
void
main(String[] args){
System.out.println(StaticFinalTest2.NONE);
//LINE 3
System.out.println(
"Static final : "
+StaticFinalTest1.getStaticFinal());
//LINE 4
}
}
When running the Test.java, you will see the output as :
StaticFinalTest2 : CONSTRUCTOR
StaticFinalTest2 : NONE = StaticFinalTest2@284d023f
StaticFinalTest1 : staticFinal = null
StaticFinalTest2 : isMode = true
StaticFinalTest2 : TLS_v11 = [Ljava.lang.String;@6e3f6813
StaticFinalTest2@284d023f
Static final : null
See line 3 of the output. Why is staticFinal null? Isn't it StaticFinalTest2.TLS_v11 which is {"TLSv1.1"}? Let's get to know why it's null now.
- When in Test.java, we first print StaticFinalTest2.NONE, at this point, StaticFinalTest2 will be initialized, hence the current thread will acquire the lock for StaticFinalTest2.
- In StaticFinalTest2, the static variables will be initialized in textual order, so static variable NONE will be initialized by creating a StaticFinalTest2 object, hence we see output line 1 and line 2.
- Then boolean variable isMode is initialized, but wait, the right side of the assignment is an expression. And the expression references StaticFinalTest1, so StaticFinalTest1 will be initialized now.
- In StaticFinalTest1, staticFinal is initialized in the static block and it is assigned with StaticFinalTest2.TLS_v11. So it tries to initialize StaticFinalTest2. However, currently StaticFinalTest2 is being initialized. So it just continues and initialized StaticFinalTest1.
- staticFinal references StaticFinalTest2.TLS_v11, but at the moment, StaticFinalTest2.TLS_v11 is not initialized yet. So the default value for StaticFinalTest2.TLS_v11 will be assigned to staticFinal, the default value is null. You see output line 3 now.
- Then StaticFinal1 will continue be initialized and the mode will be set to true. Then you see output line 4
- The rest initialization process continue in textual order
Now what if you comment line 3 in Test.java? The output is :
StaticFinalTest2 : CONSTRUCTOR
StaticFinalTest2 : NONE = StaticFinalTest2
@7d21e8ed
StaticFinalTest2 : isMode =
false
StaticFinalTest2 : TLS_v11 = [Ljava.lang.String;
@3f9935cb
StaticFinalTest1 : staticFinal = [Ljava.lang.String;
@3f9935cb
Static
final
: [Ljava.lang.String;
@3f9935cb
Below is the steps for initialization:
- When in Test.java, we first print the StaticFinalTest1.getStaticFinal(). At this point, StaticFinalTest1 is being initialized and the current thread will acquire the licj for StaticFinalTest1
- In StaticFinalTest1, staticFinal is initialized to StaticFinalTest2.TLS_V11, so StaticFinalTest2 will be initialized now.
- In StaticFinalTest2, the static variable NONE is initialized by creating a StaticFinalTest2 object, hence you see output line 1 and line 2
- Then when initializing boolean variable isMode, it refers to StaticFinalTest1 again. Now we have a recursive request for initialization of StaticFinalTest1, so it will just continue to initialize StaticFinalTest2
- The value of mode in StaticFinalTest1 will be false at the moment since it's not initialized yet. That''s why you see output line 3
- StaticFinalTest2 will continue to be initialized and StaticFinalTest2.TLS_v11 will be initialized to {"TLSv1.1"}. Then in StaticFinalTest1, the staticFinal will be assigned the value of {"TLSv1.1"}. Hence you see output line 5
- The rest of the initialization are completed in textual order
Hope this post will help you understand how recursive class initialization is handled in Java.
Link:http://www.pixelstech.net/article/1429149847-Recursive-class-initialization-in-Java
- Recursive class initialization in Java
- JAVA Class Loader Initialization
- thinking in java 笔记--类的初始化 class initialization(2007.10.10)
- java编程思想-initialization and class loading
- thinking in java(III)--initialization and cleanup
- Think In Java 笔记1 initialization & Cleanup
- Thinking in java-1 Initialization 初始化
- Relearning in JAVA: 5)Initialization & cleanup
- Recursive Lambda in C++
- java class and object initialization--java类和对象初始化
- BST_Iterative class in Java
- Static class in Java
- Recursive Blocks in Objective-C
- Recursive Type Signatures in Scala
- java.lang.LinkageError: loader constraint violation in interface itable initialization
- Initialization calls in Linux
- Static Initialization in C#
- think in java&Inner Class
- SIFT-sift.m
- .NET下的内存分配机制
- 博客生涯新的开始
- 浮点数的表示
- Sephiroth Python 分割文件以及合并文件
- Recursive class initialization in Java
- Eclipse下安装GEF和AmaterasUML
- 常用正则表达式积累
- 删除.svn文件夹
- ar删除总结
- Windows 线程笔记
- Openwrt 摄像头使用
- Entity Framework 5.0 Code First全面学习
- MySQL MHA配置常见问题