以前粗糙地看看了,面试问到了,没想起来,还是基础不行啊,还得认真总结,学知识体系要全面!!!
java类的初始化顺序
转载来自http://blog.sina.com.cn/s/blog_4cc16fc50100bjjp.html,https://blog.youkuaiyun.com/luoyoub/article/details/82874993
public class InitialOrderTest {
// 静态变量
public static String staticField = "静态变量";
// 变量
public String field = "变量";
// 静态初始化块
static {
System.out.println(staticField);
System.out.println("静态初始化块");
}
// 初始化块
{
System.out.println(field);
System.out.println("初始化块");
}
// 构造器
public InitialOrderTest() {
System.out.println("构造器");
}
public static void main(String[] args) {
new InitialOrderTest();
}
}
运行以上代码,我们会得到如下的输出结果:
1. 静态变量
2. 静态初始化块
3. 变量
4. 构造代码块
5. 构造器
下面我们再考虑继承的情况:
class Parent {
// 静态变量
public static String p_StaticField = "父类--静态变量";
// 变量
public String p_Field = "父类--变量";
protected int i = 9;
protected int j = 0;
// 静态初始化块
static {
System.out.println(p_StaticField);
System.out.println("父类--静态初始化块");
}
// 初始化块
{
System.out.println(p_Field);
System.out.println("父类--初始化块");
}
// 构造器
public Parent() {
System.out.println("父类--构造器");
System.out.println("i=" + i + ", j=" + j);
j = 20;
}
}
public class SubClass extends Parent {
// 静态变量
public static String s_StaticField = "子类--静态变量";
// 变量
public String s_Field = "子类--变量";
// 静态初始化块
static {
System.out.println(s_StaticField);
System.out.println("子类--静态初始化块");
}
// 初始化块
{
System.out.println(s_Field);
System.out.println("子类--初始化块");
}
// 构造器
public SubClass() {
System.out.println("子类--构造器");
System.out.println("i=" + i + ",j=" + j);
}
// 程序入口
public static void main(String[] args) {
System.out.println("子类main方法");
new SubClass();
}
}
最终输出结果如下
运行一下上面的代码,结果马上呈现在我们的眼前:
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
子类main方法
父类--变量
父类--初始化块
父类--构造器
i=9, j=0
子类--变量
子类--初始化块
子类--构造器
i=9,j=20
执行顺序总结:
1.父类–静态变量/父类–静态初始化块(静态变量、静态初始化块顺序取决于它们在类中出现的先后顺序)
2.子类–静态变量/子类–静态初始化块(静态变量、静态初始化块顺序取决于它们在类中出现的先后顺序)
3.子类main方法执行(执行main方法之前会进行类的加载,同时会向上加载基类也就是父类,因此相关的静态变量以及静态初始化块静态方法被载入)
4.父类–变量/父类–初始化块(变量与初始化代码块顺序取决于它们在类中出现的先后顺序)
5.父类–构造器
6.子类–变量/子类–初始化块(变量与初始化代码块顺序取决于它们在类中出现的先后顺序)
7.子类–构造器
注意:
初始化块也叫构造代码块,每次new对象时都执行
静态代码块和静态方法的区别:一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就主动执行;静态方法在类加载的时候就已经加载 可以用类名直接调用,也可以使用对象调用,静态方法时在被调用的时候才会执行,属于被动执行, 比如main方法就必须是静态的 这是程序入口
两者的区别就是:静态代码块是自动执行的; 静态方法是被调用的时候才执行的.
双亲委派模型
https://blog.youkuaiyun.com/yusimiao/article/details/99301293,https://www.jianshu.com/p/9df9d318e838暂时没看懂

双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
双亲委派模式优势
- 采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。
- 其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
- 可能你会想,如果我们在classpath路径下自定义一个名为java.lang.SingleInterge类(该类是胡编的)呢?该类并不存在java.lang中,经过双亲委托模式,传递到启动类加载器中,由于父类加载器路径下并没有该类,所以不会加载,将反向委托给子类加载器加载,最终会通过系统类加载器加载该类。但是这样做是不允许,因为java.lang是核心API包,需要访问权限,强制加载将会报出如下异常
代码块介绍
在Java中,使用{}大括号括起来的代码被称为代码块。
根据其位置和声明的不同,代码块可以分为:
- 局部代码块(普通代码块):控制变量的生命周期,提高内存利用率
- 构造代码块:可以给所有对象进行初始化
- 静态代码块:对静态属性、类进行初始化,并且只执行一次。
- 同步代码块(多线程讲解)。
构造代码块
在类中直接定义没有任何修饰符、前缀、后缀的代码块即为构造代码块。
特点:
new一个对象的时候总是先执行构造代码,再执行构造函数。
有一点需要注意构造代码不是在构造函数之前运行的,它是依托构造函数执行的。
正是由于构造代码块有这几个特性,所以它常用于如下场景:
作用:
可以给所有对象进行初始化
代码示例:
-
public class demo1 { -
public static void main(String[] args) { -
Test test = new Test(3); //构造代码块会在构造函数被调用时执行, 且在这个例子中比"this.id=id;"语句先执行,作用是给对象统一初始化数据; -
System.out.println(test); -
} -
} -
class Test{ -
int id; -
String name; -
{ -
this.id= 5; -
this.name = "测试"; -
System.out.println("这是构造代码块"); -
} -
public Test(int id) -
{ -
this.id = id; -
} -
public String toString() -
{ -
return "name: "+this.name +" , "+"id: "+ this.id ; -
} -
}
运行结果:
静态代码块
静态代码块就是用static修饰的用{}括起来的代码段
特点:
- 它是随着类的加载而执行,只执行一次,优先于构造函数
- 静态代码块其实就是给类初始化的,而构造代码块是给对象初始化的。
- 一个类中可以有多个静态代码块
作用:
对静态属性进行初始化
注意:
1.静态代码块不能存在于任何方法体内。
2 .静态代码块不能直接访问静态实例变量和实例方法,需要通过类的实例对象来访问。
代码示例:
-
public class demo01 { -
public static void main(String[] args) { -
Test t=new Test(); -
} -
} -
class Test{ -
{ -
System.out.println("构造代码块"); -
} -
public Test(){ -
System.out.println("我是构造方法"); -
} -
static { -
System.out.println("我是静态代码块"); -
} -
}
运行结果:

局部代码块
位置在方法内部
作用:
用于限定变量的生命周期,及早释放变量,提高内存利用率。
-
public void show(){ -
{ -
System.out.println("局部代码块运行!"); -
}
本文详细解析Java类的初始化顺序,包括静态变量、静态初始化块、构造代码块等关键概念及其执行顺序。并通过示例代码展示了单类和继承情况下的初始化流程。
162

被折叠的 条评论
为什么被折叠?



