Java实例化后自动执行_Java的实例化顺序(程序执行顺序)

本文详细探讨了Java程序的加载和执行顺序,包括静态和非静态成员的加载、静态代码块、构造方法等。重点阐述了在不涉及父类和涉及父类时的加载顺序,以及main方法的执行过程。通过示例代码解析了类加载的复杂情况,有助于理解Java实例化后的自动执行流程。
摘要由CSDN通过智能技术生成

加载/执行顺序:

牢记一点:

静态和非静态分开处理

使用到静态加载时,静态又分为: 静态变量, 静态代码块, 其中加载顺序是按照类中书写的先后顺序加载的

非静态加载顺序: 按照非静态书写顺序加载/执行

静态方法,实例方法只有在调用的时候才会去执行

当静态加载中遇到需要加载非静态的情况: 先加载非静态再加载静态。

下面两种情况的加载顺序

不涉及到父类子类的情况:

1) 首先将所有静态成员变量加载进来, 但是不赋值,JVM会根据属性的数据类型第一时间赋默认值

2)然互再进行赋值,即加载静态变量一一为分配内存赋值,静态变量,静态块的加载,没有优先级之分,按照书写先后顺序加载

特殊情况: 静态变量是加载类本生的实例,会比较麻烦,稍后讲解

涉及到父类的情况

父静态-->子静态  加载时不涉及构造方法,只有使用都new才会涉及到构造方法

下面将具体讲述程序执行顺序

1. main第一句是否先执行

Java程序运行时,第一件事情就是试图访问main方法,因为main相等于程序的入口,如果没有main方法,程序将无法启动,main方法更是占一个独立的线程,找到main方法后,是不是就会执行mian方法块里的第一句话呢?不是

因为main方法虽然是一个特殊的静态方法,但是还是静态方法,此时JVM会加载main方法所在的类,试图找到类中其他静态部分,即首先会找main方法所在的类。

public class JVMTest {

static{

System.out.println("Main 方法所在静态代码块 static1");

}

public static void main(String[] args) {

System.out.println("main start");

A a = new A();

System.out.println(A.width);

System.out.println(a.width);

}

static{

System.out.println("Main 方法所在静态代码块 static2");

}

}

class A{

public static int width = 100;

static{

System.out.println("静态初始化类A");

width = 30;

}

public A(){

System.out.println("创建A类的对象");

}

}

结果

Main 方法所在静态代码块 static1

Main 方法所在静态代码块 static2

main start

静态初始化类A

创建A类的对象

30

30

上例中: 先找到main方法, 然后先加载main 方法所在的类JVMTest的静态属性, 静态代码块(按照顺序加载),即使静态代码块在main方法下面也要先加载静态代码块。然后执行 main方法

2. 静态变量声明一定放在使用前面

73a6352cf4a90411bf94726ec94ecdd0.png

3. 父类,子类加载顺序

public class JVMParent {

public static int width = 100;

public static int count;

{

System.out.println("parent no static code block :" + count);

}

static{

System.out.println("parent static's count:" + count);

}

JVMParent(int a){

System.out.println("parent init one parameter");

}

JVMParent(){

System.out.println("parent init");

}

}

public class JVMSon extends JVMParent {

{

System.out.println("son no static code block :" + count);

}

static {

System.out.println("son static 1");

}

public static int count1;

JVMSon() {

System.out.println("son init:" + count);

}

static {

System.out.println("son static 2");

}

public static void main(String[] args) {

System.out.println("son main start");

JVMSon a = new JVMSon();

}

}

结果

parent static's count:0

son static 1

son static 2

son main start

parent no static code block :0

parent init

son no static code block :0

son init:0

执行顺序:

1)加载Main方法, 先要加载包含Main方法的类, 加载类就先加载父类静态变量, 静态代码块(按照书写先后顺序)--》 子类静态变量,静态代码块

2) 执行main方法

3) main 方法中调用有构造函数

父类代码块--》 父类构造函数--》子类代码块--》子类构造函数

4. 一个比较复杂的例子,如果下面的例子理解了,就撤离理解了Java的执行顺序

public class Text {

public static int k = 10;

public int a = print("a");

public static int b = print("b");

public static Text t1 = new Text("t1");

public static Text t2 = new Text("t2");

public static int i = print("i");

public static int n = 99;

public int j = print("j");

public int m = print("m");

{

print("构造块");

}

static {

print("静态块");

}

public int l = print("l");

public static int o = print("o");

public Text(String str) {

System.out.println("构造:" + (++k) + ":" + str + " i=" + i + " n=" + n);

++i;

++n;

}

public static int print(String str) {

System.out.println("print:" + (++k) + ":" + str + " i=" + i + " n=" + n);

++n;

return ++i;

}

public int p = print("p");

public static void main(String args[]) {

Text t = new Text("init");

}

}

print:11:b i=0 n=0

print:12:a i=1 n=1

print:13:j i=2 n=2

print:14:m i=3 n=3

print:15:构造块 i=4 n=4

print:16:l i=5 n=5

print:17:p i=6 n=6

构造:18:t1 i=7 n=7

print:19:a i=8 n=8

print:20:j i=9 n=9

print:21:m i=10 n=10

print:22:构造块 i=11 n=11

print:23:l i=12 n=12

print:24:p i=13 n=13

构造:25:t2 i=14 n=14

print:26:i i=15 n=15

print:27:静态块 i=16 n=99

print:28:o i=17 n=100

print:29:a i=18 n=101

print:30:j i=19 n=102

print:31:m i=20 n=103

print:32:构造块 i=21 n=104

print:33:l i=22 n=105

print:34:p i=23 n=106

构造:35:init i=24 n=107

执行顺序:

1)JVM 类加载机制中提到,类连接 (验证, 准备, 解析)中准备工作:

负责为类的类变量(非对象变量)分配内存,并设置默认初始值,准备类中每个字段、方法和实现接口所需的数据结构, 这里说的初始值都是默认的值, 并不是程序中指定的值 , 经过准备工作,类中变量的初始值为如下

k =0; b=0; t1=null; t2=null; i=0; n=0;

2)  JVM在类连接以后进行类的初始化,即给类变量赋值,按照静态属性的书写顺序执行

A: public static int k = 10;     -->  k=10

B:public static int b = print("b");   -->调用print("b")  print:11:b   i=0    n=0

C: public static Text t1 = new Text("t1");  当加载静态变量是需要先加载构造器, 那就转为先加载所有非静态属性

此时按照书写的顺序加载非静态, 如下所示

public int a = print("a"); --》 print:12:a i=1 n=1

public int j = print("j"); --》print:13:j i=2 n=2

public int m = print("m"); --》print:14:m i=3 n=3

{

print("构造块"); --》print:15:构造块 i=4 n=4

}

public int l = print("l"); --》print:16:l i=5 n=5

public int p = print("p"); --》print:17:p i=6 n=6

然后继续执行构造器

public Text(String str) {

System.out.println("构造:" + (++k) + ":" + str + " i=" + i + " n=" + n);

++i;

++n;

}

==》构造:18:t1   i=7    n=7

D:     public static Text t2 = new Text("t2");  和C的过程一模一样, 非静态的每次new都加载一次

print:19:a   i=8    n=8

print:20:j   i=9    n=9

print:21:m   i=10    n=10

print:22:构造块   i=11    n=11

print:23:l   i=12    n=12

print:24:p   i=13    n=13

构造:25:t2   i=14    n=14

E:     public static int i = print("i");  ==>print:26:i   i=15    n=15

F:      public static int n = 99;   n=99

G:

static {

print("静态块");

}

==>print:27:静态块   i=16    n=99

H:    public static int o = print("o"); ==>print:28:o   i=17    n=100

I: Text t = new Text("init");

==>

print:29:a   i=18    n=101

print:30:j   i=19    n=102

print:31:m   i=20    n=103

print:32:构造块   i=21    n=104

print:33:l   i=22    n=105

print:34:p   i=23    n=106

构造:35:init   i=24    n=107

参考: https://www..com/greatfish/p/5771548.html1·

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值