静态加载顺序
一.关键字static
1.static可以修饰成员变量、成员方法,不能修饰构造函数,构造函数是在创建对象时使用的。而static是类的属性。
2.当一个函数没有访问实例变量数据时,才能被static修饰。因为静态不能访问非静态的,在静态加载时,有可能还没有创建对象,成员变量和成员方法都是和对象有关的。
二.静态函数注意事项
1.被static修饰的函数称为类函数,非静态函数也称为实例函数
2.static可以修饰成员变量、成员方法,但是不能修饰构造函数
3.静态函数是在类加载的时候就在内存中加载完成,可以直接运行的函数。(只要是函数最终都要进入栈内存,方法是什么时候调用,什么时候执行,不调用不执行。)
4.非静态函数在类加载完成之后,通过new在堆中开辟内存空间,然后通过对象调用函数。
5.静态不能访问非静态
因为静态函数在类加载完成可以直接通过类名调用,而这时有可能还没有创建对象,非静态函数是依赖对象的。
6.非静态可以访问静态
因为当非静态函数可以运行,那么说明类中一定创建了对象,说明对象所在的类已经加载完成,那么非静态就可以访问静态。
三.类和对象的加载过程
1.类加载过程:
① JVM启动,加载所需要的class文件② JVM加载class文件时,会把所有的静态内容(静态成员变量、静态方法、静态代码块)都先加载到方法区中的静态区中。
③ 静态加载完成之后,JVM开始给所有的成员变量默认初始化,静态成员变量开辟空间。
④ 当给类中的所有静态成员变量默认初始化完成,开始按照代码的顺序依次执行(遇到静态代码块就执行,遇到静态成员变量就显示初始化)
⑤ 静态都执行完毕,类才彻底加载完成
2.对象的加载过程:
② 给对象所属的类的非静态成员变量分配空间并进行默认初始化
③ 在JVM自动调取构造函数时先执行隐式三步
- super()区访问父类构造,对父类进行初始化
- 给非静态成员变量进行显示赋值
- 执行构造代码块
⑤ 构造函数执行完毕,对象创建完成。
四.静态内存图解
StaticDemo类
- package cn.jason03;
- /**
- * 这是static的用法
- * @author Jason
- *
- */
- class Demo {
- int x;
- static int y = 3;
- // 静态代码块
- static {
- System.out.println("静态代码块");
- }
- // 定义构造代码块
- {
- System.out.println("我是构造代码块");
- System.out.println("x=" + x);
- }
- //构造函数
- public Demo() {
- }
- static void print() {
- System.out.println("y=" + y);
- }
- void show() {
- System.out.println("x=" + x + " y=" + y);
- }
- }
- class StaticDemo {
- public static void main(String[] args) {
- //类名调用print方法
- Demo.print();
- //创建对象
- Demo d = new Demo();
- //给成员变量x赋值
- d.x = 10;
- //用对象调用show方法
- d.show();
- }
- }
StaticCode类
- package cn.jason03;
- /**
- * 静态属性执行顺序1
- *
- * @author Jason
- */
- class StaticCode {
- static int x = 10;
- static int y = show();
- static int show() {
- System.out.println("show..........x = " + x);
- System.out.println("show..........y = " + y);
- return 100;
- }
- // 静态代码块
- static {
- System.out.println("静态代码块运行....y= " + y);
- }
- void print() {
- System.out.println("....................");
- }
- }
- public class StaticCodeDemo {
- public static void main(String[] args) {
- new StaticCode().print();
- }
- }
内存图解:
五.颠覆思维的小题目
- package cn.jason07;
- public class StaticInitTest {
- /*static {
- value = 10;
- print("静态代码块");
- }*/
- static int value = getValue();
- static { // 通过静态初始化块为name变量初始化
- System.out.println("静态代码块中value的值=" + value);
- name = "周杰伦";
- }
- static {
- value = 10;
- print("静态代码块");
- }
- static String name = "林青霞"; // 定义静态变量
- public static void print(String s) {
- System.out.println("value的值=" + value + " " + "名字是:"+name);
- }
- public static int getValue() {
- return ++value;
- }
- public static void main(String[] args) {
- System.out.println("value的值:" + StaticInitTest.value);
- System.out.println("name的值:" + StaticInitTest.name);
- }
- }
静态代码块中value的值=1
value的值=10 名字是:周杰伦
value的值:10
name的值:林青霞
- package cn.jason07;
- public class StaticInitTest {
- static {
- value = 10;
- print("静态代码块");
- }
- static int value = getValue();
- static { // 通过静态初始化块为name变量初始化
- System.out.println("静态代码块1中value的值=" + value);
- name = "周杰伦";
- }
- /*static {
- value = 10;
- print("静态代码块2");
- }*/
- static String name = "林青霞"; // 定义静态变量
- public static void print(String s) {
- System.out.println("value的值=" + value + " " + "名字是:"+name);
- }
- public static int getValue() {
- return ++value;
- }
- public static void main(String[] args) {
- System.out.println("value的值:" + StaticInitTest.value);
- System.out.println("name的值:" + StaticInitTest.name);
- }
- }
value的值=10 名字是:null
静态代码块1中value的值=11
value的值:11
name的值:林青霞
注意:
- 静态函数是在类加载的时候就在内存中加载完成,可以直接运行的函数。静态属性优先于对象存在的,静态属性是类所共享的,静态成员变量赋值可以在定义静态变量之前,但是输出不能在定义静态变量之前。(只要是函数最终都要进入栈内存,方法是什么时候调用,什么时候执行,不调用不执行。)
- 对于对象而言,栈内存的引用地址不是对象,仅仅是为堆内存中对象分配内存空间时随机分配的地址值而已,真正的对象在堆内存。指向只是方便使用成员属性。
- 凡是对于静态可以不用创建对象,直接可以用类名调用。凡是对于非静态,如要访问非静态成员方法和成员属性,那么需要想方设法创建对象来访问。(为什么说想方设法呢?比如非静态的内部类,如果非静态内部类被private修饰,那么只能在外部类里创建对象来访问被private修饰的内部类属性和行为,在外部类之外是不能访问的。)
第二道题:
- package cn.jason01;
- /**
- * 静态加载顺序
- *
- * @author Jason
- *
- */
- public class StaticTest {
- public static void main(String[] args) {
- staticFunction();
- show();
- }
- static StaticTest st = new StaticTest();
- static {
- System.out.println("1");
- }
- {
- System.out.println("2");
- }
- public StaticTest() {
- System.out.println("3");
- System.out.println("构造函数中的.....a=" + a + " b=" + b);
- }
- public static void staticFunction() {
- System.out.println("4");
- // System.out.println("b=="+b);
- }
- int a = 110;
- static int b = 112;
- public static void show() {
- System.out.println("show..........b=" + b);
- }
- }
输出结果:
2
3
构造函数中的.....a=110 b=0
1
4
show..........b=112
第二道题解析:
①运行时,JVM先加载main函数所在的类,也就是StaticTest类。加载就是把StaticTest类的字节码全部放在方法区,与此同时只有静态成员变量先默认初始化了,其他都没有执行只是放在里面。然后按照代码顺序进行执行。所以第一步先执行static StaticTest st = new StaticTest()。
②在堆内存new StaticTest()开辟一个空间,随机分配十六进制地址值,非静态成员变量这个空间在开辟一个小空间,默认初始化值,int a=0。
③现在JVM自动调用构造函数,所以public StaticTest() {}进栈内存,先执行隐式三步。隐式三步第二步给非静态成员显示初始化,这是int a=110;隐式三步第三步就是执行构造代码块(反编译之后一目了然),所以先输出2。隐式三步执行完,现在执行构造代码块中的其它代码,所以输出3,构造函数中的.........a=110,b=0
④按照代码顺序向下执行,那么开始执行静态代码块,输出1
⑤给静态变量b显示初始化,这时b=112,然后才调用方法,一定是先给静态显示初始化完毕才调用方法的(对于本题是这样的),输出4.如果把staticFunction函数中的注释放开,如果b=112,那么说明静态变量显示赋值在调用方法之前完成。放开注释结果正是b=112,说明验证是正确的。
⑥在调用show方法,这时也能验证执行时按照代码的顺序执行的。输出show..........b=112
总结:
1.加载时只对静态成员变量默认初始化值,其它内容都只加载不执行。
2.执行是按照代码顺序执行的。
一.关键字static
1.static可以修饰成员变量、成员方法,不能修饰构造函数,构造函数是在创建对象时使用的。而static是类的属性。
2.当一个函数没有访问实例变量数据时,才能被static修饰。因为静态不能访问非静态的,在静态加载时,有可能还没有创建对象,成员变量和成员方法都是和对象有关的。
二.静态函数注意事项
1.被static修饰的函数称为类函数,非静态函数也称为实例函数
2.static可以修饰成员变量、成员方法,但是不能修饰构造函数
3.静态函数是在类加载的时候就在内存中加载完成,可以直接运行的函数。(只要是函数最终都要进入栈内存,方法是什么时候调用,什么时候执行,不调用不执行。)
4.非静态函数在类加载完成之后,通过new在堆中开辟内存空间,然后通过对象调用函数。
5.静态不能访问非静态
因为静态函数在类加载完成可以直接通过类名调用,而这时有可能还没有创建对象,非静态函数是依赖对象的。
6.非静态可以访问静态
因为当非静态函数可以运行,那么说明类中一定创建了对象,说明对象所在的类已经加载完成,那么非静态就可以访问静态。
三.类和对象的加载过程
1.类加载过程:
① JVM启动,加载所需要的class文件② JVM加载class文件时,会把所有的静态内容(静态成员变量、静态方法、静态代码块)都先加载到方法区中的静态区中。
③ 静态加载完成之后,JVM开始给所有的成员变量默认初始化,静态成员变量开辟空间。
④ 当给类中的所有静态成员变量默认初始化完成,开始按照代码的顺序依次执行(遇到静态代码块就执行,遇到静态成员变量就显示初始化)
⑤ 静态都执行完毕,类才彻底加载完成
2.对象的加载过程:
② 给对象所属的类的非静态成员变量分配空间并进行默认初始化
③ 在JVM自动调取构造函数时先执行隐式三步
- super()区访问父类构造,对父类进行初始化
- 给非静态成员变量进行显示赋值
- 执行构造代码块
⑤ 构造函数执行完毕,对象创建完成。
四.静态内存图解
StaticDemo类
- package cn.jason03;
- /**
- * 这是static的用法
- * @author Jason
- *
- */
- class Demo {
- int x;
- static int y = 3;
- // 静态代码块
- static {
- System.out.println("静态代码块");
- }
- // 定义构造代码块
- {
- System.out.println("我是构造代码块");
- System.out.println("x=" + x);
- }
- //构造函数
- public Demo() {
- }
- static void print() {
- System.out.println("y=" + y);
- }
- void show() {
- System.out.println("x=" + x + " y=" + y);
- }
- }
- class StaticDemo {
- public static void main(String[] args) {
- //类名调用print方法
- Demo.print();
- //创建对象
- Demo d = new Demo();
- //给成员变量x赋值
- d.x = 10;
- //用对象调用show方法
- d.show();
- }
- }
StaticCode类
- package cn.jason03;
- /**
- * 静态属性执行顺序1
- *
- * @author Jason
- */
- class StaticCode {
- static int x = 10;
- static int y = show();
- static int show() {
- System.out.println("show..........x = " + x);
- System.out.println("show..........y = " + y);
- return 100;
- }
- // 静态代码块
- static {
- System.out.println("静态代码块运行....y= " + y);
- }
- void print() {
- System.out.println("....................");
- }
- }
- public class StaticCodeDemo {
- public static void main(String[] args) {
- new StaticCode().print();
- }
- }
内存图解:
五.颠覆思维的小题目
- package cn.jason07;
- public class StaticInitTest {
- /*static {
- value = 10;
- print("静态代码块");
- }*/
- static int value = getValue();
- static { // 通过静态初始化块为name变量初始化
- System.out.println("静态代码块中value的值=" + value);
- name = "周杰伦";
- }
- static {
- value = 10;
- print("静态代码块");
- }
- static String name = "林青霞"; // 定义静态变量
- public static void print(String s) {
- System.out.println("value的值=" + value + " " + "名字是:"+name);
- }
- public static int getValue() {
- return ++value;
- }
- public static void main(String[] args) {
- System.out.println("value的值:" + StaticInitTest.value);
- System.out.println("name的值:" + StaticInitTest.name);
- }
- }
静态代码块中value的值=1
value的值=10 名字是:周杰伦
value的值:10
name的值:林青霞
- package cn.jason07;
- public class StaticInitTest {
- static {
- value = 10;
- print("静态代码块");
- }
- static int value = getValue();
- static { // 通过静态初始化块为name变量初始化
- System.out.println("静态代码块1中value的值=" + value);
- name = "周杰伦";
- }
- /*static {
- value = 10;
- print("静态代码块2");
- }*/
- static String name = "林青霞"; // 定义静态变量
- public static void print(String s) {
- System.out.println("value的值=" + value + " " + "名字是:"+name);
- }
- public static int getValue() {
- return ++value;
- }
- public static void main(String[] args) {
- System.out.println("value的值:" + StaticInitTest.value);
- System.out.println("name的值:" + StaticInitTest.name);
- }
- }
value的值=10 名字是:null
静态代码块1中value的值=11
value的值:11
name的值:林青霞
注意:
- 静态函数是在类加载的时候就在内存中加载完成,可以直接运行的函数。静态属性优先于对象存在的,静态属性是类所共享的,静态成员变量赋值可以在定义静态变量之前,但是输出不能在定义静态变量之前。(只要是函数最终都要进入栈内存,方法是什么时候调用,什么时候执行,不调用不执行。)
- 对于对象而言,栈内存的引用地址不是对象,仅仅是为堆内存中对象分配内存空间时随机分配的地址值而已,真正的对象在堆内存。指向只是方便使用成员属性。
- 凡是对于静态可以不用创建对象,直接可以用类名调用。凡是对于非静态,如要访问非静态成员方法和成员属性,那么需要想方设法创建对象来访问。(为什么说想方设法呢?比如非静态的内部类,如果非静态内部类被private修饰,那么只能在外部类里创建对象来访问被private修饰的内部类属性和行为,在外部类之外是不能访问的。)
第二道题:
- package cn.jason01;
- /**
- * 静态加载顺序
- *
- * @author Jason
- *
- */
- public class StaticTest {
- public static void main(String[] args) {
- staticFunction();
- show();
- }
- static StaticTest st = new StaticTest();
- static {
- System.out.println("1");
- }
- {
- System.out.println("2");
- }
- public StaticTest() {
- System.out.println("3");
- System.out.println("构造函数中的.....a=" + a + " b=" + b);
- }
- public static void staticFunction() {
- System.out.println("4");
- // System.out.println("b=="+b);
- }
- int a = 110;
- static int b = 112;
- public static void show() {
- System.out.println("show..........b=" + b);
- }
- }
输出结果:
2
3
构造函数中的.....a=110 b=0
1
4
show..........b=112
第二道题解析:
①运行时,JVM先加载main函数所在的类,也就是StaticTest类。加载就是把StaticTest类的字节码全部放在方法区,与此同时只有静态成员变量先默认初始化了,其他都没有执行只是放在里面。然后按照代码顺序进行执行。所以第一步先执行static StaticTest st = new StaticTest()。
②在堆内存new StaticTest()开辟一个空间,随机分配十六进制地址值,非静态成员变量这个空间在开辟一个小空间,默认初始化值,int a=0。
③现在JVM自动调用构造函数,所以public StaticTest() {}进栈内存,先执行隐式三步。隐式三步第二步给非静态成员显示初始化,这是int a=110;隐式三步第三步就是执行构造代码块(反编译之后一目了然),所以先输出2。隐式三步执行完,现在执行构造代码块中的其它代码,所以输出3,构造函数中的.........a=110,b=0
④按照代码顺序向下执行,那么开始执行静态代码块,输出1
⑤给静态变量b显示初始化,这时b=112,然后才调用方法,一定是先给静态显示初始化完毕才调用方法的(对于本题是这样的),输出4.如果把staticFunction函数中的注释放开,如果b=112,那么说明静态变量显示赋值在调用方法之前完成。放开注释结果正是b=112,说明验证是正确的。
⑥在调用show方法,这时也能验证执行时按照代码的顺序执行的。输出show..........b=112
总结:
1.加载时只对静态成员变量默认初始化值,其它内容都只加载不执行。
2.执行是按照代码顺序执行的。