Java的实例化顺序(程序执行顺序)

原文链接:https://blog.csdn.net/u011517841/article/details/82657047?utm_source=app&app_version=4.10.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

加载/执行顺序:
牢记一点:

静态和非静态分开处理

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

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

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

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


下面两种情况的加载顺序

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

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. 静态变量声明一定放在使用前面

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值