类的初始化及加载
1. 构造器初始化
例如下面这个例子
public class Test{
int i;
Test(){
i=7;
}
}
根据java的特性,
先i=0。 再i=7
在加载一个类的时候,(先不谈静态代码块)首先把他的成员变量初始化,对于基本类型就是0之类的。
对于引用类型 则是Null。然后在构造函数中初始化他们。
2. 含静态代码块的初始化
静态代码块是一个类被加载或使用的第一个执行的地方
(不需要实例化,即使调用类中的静态方法和数据也算是使用)
java运行类是按需运行,需要再加载。不需要就不会加载。
值得注意的是 静态代码块或者静态变量 加载要先于main方法
这个很容易忘记,常规思想总是把main当做程序运行的入口
下面是一个例子
package com.example.demo;
public class Test {
static {
// 1
System.out.println("我是静态代码块");
}
public static void main(String[] args){
// 5 and 6 and 7
System.out.print("main方法中");
new One();
new Two();
}
// 2
static One one = new One();
// 3
static Two two = new Two();
}
class One{
One(){
System.out.println("我是静态实例one");
}
}
class Two{
Two(){
// 4
new One();
System.out.println("我是静态实例two");
}
}
运行结果
我是静态代码块
我是静态实例one
我是静态实例one
我是静态实例two
main方法中我是静态实例one
我是静态实例one
我是静态实例two
运行结果的语句的顺序在代码中有体现
3. 关于继承的初始化
直接看例子
package com.example.demo;
// 运行类第一个检查的是下面这句话
public class Test extends TestFather{ // 向上查testfather
// 上面这句 查找原始祖先,没有重写Object 所以祖先就是GrandFa
static {
System.out.println("Test 被加载了");
}
public static void main(String[] args){
Test test = new Test();
}
private int i;
Test(){
System.out.println("我是Test");
System.out.println("i的值为"+i);
}
}
class TestFather extends TestGrandFa{
static {
System.out.println("TestFather 被加载了");
}
private int j;
TestFather(){
System.out.println("我是TestFather");
System.out.println("j的值为"+j);
}
}
class TestGrandFa{
static {
System.out.println("TestGrandFa 被加载了");
}
private int k;
TestGrandFa(){
System.out.println("我是GrandFa");
System.out.println("k的值为"+k);
}
}
输出结果为
TestGrandFa 被加载了
TestFather 被加载了
Test 被加载了
我是GrandFa
k的值为0
我是TestFather
j的值为0
我是Test
i的值为0
由结果可以知道
创建一个对象,会先从直接父类开始找,一层一层找上去。直到父类为Object
把这些父类压入栈,从栈顶开始初始化对象。再弹出 继续下一个栈顶直到栈为空。