【文章转载自】:【java】类的加载和对象的构造(实例化)过程及顺序
1.1 什么类的加载load?(Node类的加载)
答.从硬盘上找到Node.class,解析该文件内容,生成Node类,把Node类的信息存放在内存的方法区
1.2 什么情况下回触发类的加载?并且该类不在内存中
(1)按需加载(懒加载过程)
a.实例化该类的一个对象 new Node(1);
b.使用类的静态属性或者静态方法 Main.merge(…)
c.用到子类,必须要有父类 new CNode
d.先加载父类的静态代码块,再加载子类的静态代码块
1.3 其他规则
静态属性的初始化顺序:
按代码的书写顺序,执行
a.静态属性定义时的初始化
b.静态代码
2.代码块
代码块定义:使用“{}”定义的一段代码;
构造代码块是跟着对象的加载而加载的。
2.1 普通代码块
普通代码块:定义在方法中的代码块;
-
public
class Test1 {
-
public static void main(String[] args) {
-
{
-
//普通代码块
-
int a=
10;
-
System.out.println(a);
-
}
-
int a=
20;
-
System.out.println(a);
-
}
-
}
2.2 构造块
构造块:定义在类中的代码块(不加修饰符)
-
class A{
-
//定义在类中,不加任意修饰符
-
{
-
System.out.println(
"A的构造块");
-
}
-
//构造方法
-
public A(){
-
System.out.println(
"A的构造方法");
-
}
-
}
-
public
class Test2 {
-
public static void main(String[] args) {
-
new A();
-
new A();
-
}
-
}
通过上述代码可以发现:构造块优先于构造方法执行,每产生一个新的对象就调用一次构造块。所以构造块可以进行简单的逻辑操作(在调用构造方法之前)。
2.3 静态代码块
静态代码块:使用static定义的代码块,它是跟着类的加载而加载的。
根据静态代码块所在的类不同又可分为以下两种类型:
1.在非主类中的静态代码块
2.在主类中的静态代码块
2.3.1 在非主类中的静态代码块
-
class B{
-
//构造块
-
{
-
System.out.println(
"B类的构造块");
-
}
-
//代码方法
-
public B(){
-
System.out.println(
"B类的构造方法");
-
}
-
//静态代码块
-
static {
-
System.out.println(
"B类的静态代码块");
-
}
-
}
-
public
class Test3 {
-
public static void main(String[] args) {
-
System.out.println(
"==============================");
-
new B();
-
new B();
-
System.out.println(
"==============================");
-
}
-
}
可以发现:
1.在非主类的静态代码块中,在类加载时执行,优先于构造块执行
2.无论产生多少实例化对象,静态代码块只执行一次
静态块的主要作用是为static属性进行初始化!
2.3.2 在主类中的静态代码块
-
public
class Test4 {
-
//构造块
-
{
-
System.out.println(
"Test4类的构造块");
-
}
-
-
//构造方法
-
public Test4(){
-
System.out.println(
"Test4类的构造方法");
-
}
-
//静态代码块
-
static {
-
System.out.println(
"Test4类的静态代码块");
-
}
-
-
public static void main(String[] args) {
-
System.out.println(
"===========================");
-
new Test4();
-
new Test4();
-
System.out.println(
"===========================");
-
}
-
}
在主类中定义的静态块,优先于主方法(main)执行,在JVM启动时执行,当编译执行时JVM会首先加载主类,此时主类中的静态代码块就会执行。
3.对象的构造/实例化 new Node
3.1 规则
1.优先初始化父类的属性,(和下面的执行顺序相同)
2.按照下面的顺序执行初始化
a.按照代码书写顺序,执行定义时和构造代码块
b.再去执行构造方法
3.静态代码块只在加载时执行一次,先执行父类的静态代码块,再执行子类的静态代码块。
3.2关于执行顺序的问题
1.父类的加载在子类之前
2.父类的构造方法在子类之前调用
3.static属性初始化是在类的加载时执行(按顺序执行)
1)定义时初始化
2)构造代码块时初始化
4.普通属性初始化是在对象的构造时执行(按顺序执行)
1)定义时初始化
2)构造代码块时初始化
3)构造方法时初始化
5.只有用到类,才会加载类
-
class Hello{
-
//构造方法
-
public Hello(){
-
System.out.println(
"1.Hello父类的构造方法");
-
}
-
//非静态代码块
-
{
-
System.out.println(
"2.Hello父类非静态代码块");
-
}
-
//静态代码块
-
static{
-
System.out.println(
"3.Hello父类静态代码块");
-
}
-
}
-
public
class HelloA extends Hello{
-
public HelloA(){
-
System.out.println(
"4.helloA构造方法");
-
}
-
//非静态代码块
-
{
-
System.out.println(
"5.HelloA非静态代码块");
-
}
-
//静态代码块
-
static{
-
System.out.println(
"6.HelloA静态代码块");
-
}
-
-
public static void main(String[] args) {
-
System.out.println(
"7.---start---");
-
new HelloA();
-
new HelloA();
-
System.out.println(
"8.---end---");
-
}
-
}
按照上面讲的执行顺序执行:因为先用到了主类HeoolA,所以先加载了静态代码块;
执行结果:
-
class Hello1{
-
//构造方法
-
public Hello1(){
-
System.out.println(
"1.Hello1父类的构造方法");
-
}
-
//非静态代码块
-
{
-
System.out.println(
"2.Hello1父类非静态代码块");
-
}
-
//静态代码块
-
static{
-
System.out.println(
"3.Hello1父类静态代码块");
-
}
-
}
-
class Hello2 extends Hello1 {
-
public Hello2() {
-
System.out.println(
"4.hello2构造方法");
-
}
-
-
//非静态代码块
-
{
-
System.out.println(
"5.Hello2非静态代码块");
-
}
-
-
//静态代码块
-
static {
-
System.out.println(
"6.Hello2静态代码块");
-
}
-
-
}
-
public
class Test{
-
public static void main(String[] args) {
-
System.out.println(
"7.---start---");
-
new Hello2();
-
new Hello2();
-
System.out.println(
"8.---end---");
-
}
-
}
运行结果:
注:代码块的内容参考本文章!!!