Java中main方法,静态,非静态的执行顺序详解

本文深入解析Java程序执行的顺序,从main方法、静态与非静态的执行机制,到类加载、对象创建的过程,以及静态与动态属性、方法的初始化顺序。通过实例代码详细解释了Java的初始化原则和执行流程。

深入了解Java程序执行顺序

Java中main方法,静态,非静态的执行顺序详解

Java程序运行时,第一件事情就是试图访问main方法,因为main相等于程序的入口,如果没有main方法,程序将无法启动,main方法更是占一个独立的线程,找到main方法后,是不是一定执行mian方法块里的第一句话呢?答案是不一定。
看看下面两种最常见的情况:

第一种情况:
main方法在一个具有其他方法或属性的类中;

public class TestStatic {
	public static String name;
    public TestStatic() {
    }
    
    static{
    	System.out.println("首先执行静态块!");
    }
    public static void get() {
        System.out.println("Test start");
    }
    public static void main(String[] args) {
        System.out.println("main start");
    }

}

执行结果:

//首先执行静态块!
main start

第二种情况:
main方法在一个没有其他方法或属性的类中;

public class Test {
    public static void main(String[] args) {
        System.out.println("main start");
    }
}

执行结果:

main start

分析:

因为静态部分是依赖于类,而不是依赖于对象存在的,所以静态部分的加载优先于对象存在。
当找到main方法后,因为main方法虽然是一个特殊的静态方法,但是还是静态方法,此时JVM会加载main方法所在的类,试图找到类中其他静态部分,即首先会找main方法所在的类。

执行顺序大致分类:
  1. 静态属性,静态方法声明,静态块。
  2. 动态属性,普通方法声明,构造块。
  3. 构造方法。
1.1 静态:

当加载一个类时,JVM会根据属性的数据类型第一时间赋默认值(一举生成的)。然后再进行静态属性初始化,并为静态属性分配内存空间,静态方法的声明,静态块的加载,没有优先级之分,按出现顺序执行,静态部分仅仅加载一次。至此为止,必要的类都已经加载完毕,对象就可以被创建了。

1.2 普通:

当new一个对象时,此时会调用构造方法,但是在调用构造方法之前,(此刻1.1已经完成,除非被打断而暂停)执行动态属性定义并设置默认值(一举生成的)。然后动态属性初始化,分配内存,构造块,普通方法声明(只是加载,它不需要初始化,只有调用它时才分配内存,当方法执行完毕后内存立即释放),没有优先级之分,按出现顺序执行。最后进行构造方法中赋值。当再次创建一个对象,不再执行静态部分,仅仅重复执行普通部分。

注意:如果存在继承关系,创建对象时,依然会首先进行动态属性进行定义并设默认值,然后父类的构造器才会被调用,其他一切都是先父类再子类(因为子类的static初始化可能会依赖于父类成员能否被正确初始化),如果父类还有父类,依次类推,不管你是否打算产生一个该父类的对象,这都是自然发生的。

下面是一道小程序:
代码部分:
class A {
    public A() {
        System.out.println("A的构造方法");
    }

    public static int j = print();

    public static int print() {
        System.out.println("A print");
        return 521;
    }
}

public class TestStatic extends A {
    public TestStatic() {
        System.out.println("TestStatic的构造方法");
    }

    public static int k = print();

    public static int print() {
        System.out.println("Test print");
        return 522;
    }

    public static void main(String[] args) {
        System.out.println("main start");
        TestStatic t1 = new TestStatic();
    }
}
运行结果:
A print
Test print
main start
A的构造方法
TestStatic的构造方法
下面是一道阿里巴巴的面试题:非常经典,可以不断的改变程序的顺序,来找到执行顺序机制。
代码部分:
public class TestStatic {
    public static int k = 0;
    public static TestStatic t1 = new TestStatic("t1");
    public static TestStatic t2 = new TestStatic("t2");
    public static int i = print("i");
    public static int n = 99;
    public int j = print("j");

    {
        print("构造块");
    }
    static {
        print("静态块");
    }

    public TestStatic(String str) {
        System.out.println((++k) + ":" + str + "   i=" + i + "    n=" + n);
        ++i;
        ++n;
    }

    public static int print(String str) {
        System.out.println((++k) + ":" + str + "   i=" + i + "    n=" + n);
        ++n;
        return ++i;
    }

    public static void main(String args[]) {
        TestStatic t = new TestStatic("init");
    }
}
运行结果:
1:j   i=0    n=0
2:构造块   i=1    n=1
3:t1   i=2    n=2
4:j   i=3    n=3
5:构造块   i=4    n=4
6:t2   i=5    n=5
7:i   i=6    n=6
8:静态块   i=7    n=99
9:j   i=8    n=100
10:构造块   i=9    n=101
11:init   i=10    n=102
总结:只要按照这个步骤,遇到这一类问题就可以解决了。
  • 1-3:类加载过程,不涉及构造方法
  • 1-5: 实例化过程,涉及构造方法
1. 类中所有属性的默认值(一举而成)
2. 父类静态属性初始化,静态块,静态方法的声明(按出现顺序执行)
3. 子类静态属性初始化,静态块,静态方法的声明 (按出现顺序执行)
4. 调用父类的构造方法,
  • 首先父类的非静态成员初始化,构造块,普通方法的声明(按出现顺序执行)
  • 然后父类构造方法
5. 调用子类的构造方法,
  • 首先子类的非静态成员初始化,构造块,普通方法的声明(按出现顺序执行)
  • 然后子类构造方法
(注意:类加载过程中,可能调用了实例化过程(因为static可以修饰方法,属性,代码块,内部类),此时则会暂停类加载过程而先执行实例化过程(被打断),执行结束再进行类加载过程,上面阿里那道面试题就是典型的暂停类加载。
Java程序的初始化3个原则(优先级依次递减)
1. 静态对象(变量) > 非静态对象(变量):静态对象(变量)只是初始化一次,而非静态对象(变量)可以初始化很多次;
2, 父类 >子类;
3. 按照成员变量的定义顺序进行初始化
Java程序的初始化是通过不同的代码块来完成的。那么,类加载的顺序是:
1. 父类的静态对象(成员变量)和静态代码块;
2. 子类的静态对象(成员变量)和静态代码块;
3. 父类非静态对象(成员变量)和非静态代码块;
4. 父类构造函数;
5. 子类的非静态对象(成员变量)和非静态代码块;
6. 子类的构造函数。
静态块:用static声明;JVM加载类的时候执行,仅会执行一次(静态代码块按照声明顺序执行);静态代码块的作用完成类的初始化;
构造块:类中直接用{}定义;每一次创建对象的时候执行;
执行顺序的优先级:静态块>main()>构造块>构造方法

参考文章:
https://www.cnblogs.com/greatfish/p/5771548.html
https://blog.csdn.net/ycd500756/article/details/78157478

## 介绍## 01、数据介绍中国高技术产业统计年鉴整理与分析,揭示高技术产业的地区差异与发展趋势!随着科技的不断进步和创新驱动发展的深入实施,中国高技术产业已成为推动经济发展的重要力量。为了更好地了解高技术产业在各地区的发展情况,我们特别整理了中国高技术产业统计年鉴地区版。通过对各地区的比较和分析,我们可以更加清晰地看到高技术产业在不同地域的发展特点、优势与不足,为未来产业发展提供有价值的参考。数据名称:中国高技术产业统计年鉴数据年份:2000-2022年## 02、数据指标企业数 从业人员年平均人数 当年价总产值 资产总计 主营业务收入 利润总额 利税 出口交货值 R&D活动人员折合全时当量 R&D经费内部支出 人员劳务费 仪器和设备 政府资金 企业资金 R&D经费外部支出 新产品开发项目数 新产品开发经费支出 新产品产值 新产品销售收入 新产品出口销售收入 专利申请数 发明专利申请数 拥有发明专利数 技术改造经费支出 技术引进经费支出 消化吸收经费支出 购买国内技术经费支出 有研发机构的企业数 研发机构数 机构人员 机构经费支出 仪器设备经费 有R&D活动的企业数 R&D人员 全时人员 研究人员 新开工项目个数 全部建成或投产项目个数 项目建成投产率 更新改造项目建成投产率 投资额 基本建设投资额 更新改造投资额 施工项目个数 新增固定资产……692个指标
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值