Java中的类加载顺序
来源:互联网 发布:mac笔记本电脑价格 编辑:程序博客网 时间:2024/05/16 19:32
今天来研究一下Java中类的加载顺序。
一般情况:
Demo1
首先看父类:
public class Father { static { System.out.println("这是 Father 的静态代码块"); } { System.out.println("这是 Father 的代码块"); } public Father() { System.out.println("这是 Father 的构造方法"); }}
再看子类:
public class Son extends Father{ static { System.out.println("这是 Son 的静态代码块"); } { System.out.println("这是 Son 的代码块"); } public Son(){ System.out.println("这是 Son 的构造方法"); }}
然后调用代码:
Son son = new Son();
运行结果如下:
这是 Father 的静态代码块这是 Son 的静态代码块这是 Father 的代码块这是 Father 的构造方法这是 Son 的代码块这是 Son 的构造方法
根据以上过程,其实我们可以发现其中的规律了:
1.类加载的时候,如果有父类,会先初始化父类。
2.如果有静态的,就先加载静态的,然后再加载非静态的。
Demo2
把父类和子类稍作修改,分别加了一个静态的成员变量。
父类:
public class Father { private static Father father = new Father(); static { System.out.println("这是 Father 的静态代码块"); } { System.out.println("这是 Father 的代码块"); } public Father() { System.out.println("这是 Father 的构造方法"); }}
子类:
public class Son extends Father{ private static Son son = new Son(); public Son(){ System.out.println("这是 Son 的构造方法"); } static { System.out.println("这是 Son 的静态代码块"); } { System.out.println("这是 Son 的代码块"); }}
同样调用代码:
Son son = new Son();
运行结果如下:
这是 Father 的代码块这是 Father 的构造方法这是 Father 的静态代码块这是 Father 的代码块这是 Father 的构造方法这是 Son 的代码块这是 Son 的构造方法这是 Son 的静态代码块这是 Father 的代码块这是 Father 的构造方法这是 Son 的代码块这是 Son 的构造方法
这次结果和上次不太一样,这是因为Father和Son中分别有一个静态成员变量,并且给静态成员变量赋值的时候还调用了各自的构造方法。
我们可以得到如下结论:
1.代码块一定会在构造方法之前加载。
2.静态代码块只会加载一次,同理静态成员变量也是。
如果把上面的两个成员变量都改成非静态的,编译器就会抛出内存溢出异常。因为非静态成员变量是属于对象的,每次创建新的对象时,都会初始化对应的非静态成员变量。然后就出现了构造方法的递归调用。
总结
1.初始化一个类时,如果它有父类,会先去初始化父类。
2.先加载静态的,再加载非静态的。
3.静态的成员变量或者静态的方法块随着类的加载而加载,如果类加载过了,就不用加载了。
4.普通代码块和构造方法都是随着对象的创建而加载,每新创建一个对象,都会加载一次。而且普通代码块在构造方法之前加载。
特殊情况
Demo3
父类:
public class Father { public static String value = "123"; static { System.out.println("这是 Father 的静态代码块"); } { System.out.println("这是 Father 的代码块"); } public Father() { System.out.println("这是 Father 的构造方法"); }}
子类:
public class Son extends Father{ public Son(){ System.out.println("这是 Son 的构造方法"); } static { System.out.println("这是 Son 的静态代码块"); } { System.out.println("这是 Son 的代码块"); }}
调用代码:
public static void main(String[] args) { System.out.println(Son.value); }
运行结果如下:
这是 Father 的静态代码块123
得出结论:通过子类引用父类的静态字段,不会导致子类初始化。
Demo4
父类
public class Father { static { System.out.println("这是 Father 的静态代码块"); } { System.out.println("这是 Father 的代码块"); } public Father() { System.out.println("这是 Father 的构造方法"); }}
子类:
public class Son extends Father{ public Son(){ System.out.println("这是 Son 的构造方法"); } static { System.out.println("这是 Son 的静态代码块"); } { System.out.println("这是 Son 的代码块"); }}
调用代码:
public static void main(String[] args) { SuperClass[] sca = new SuperClass[10]; }
运行结果为空。
得出结论:通过数组定义来引用类,不会触发此类的初始化。
Demo5
Son类:
public class Son { public static final String HELLOWORLD = "hello world"; public Son() { System.out.println("这是 Son 的构造方法"); } static { System.out.println("这是 Son 的静态代码块"); } { System.out.println("这是 Son 的代码块"); }}
调用代码:
public static void main(String[] args) { System.out.println(Son.HELLOWORLD); }
运行结果如下:
hello world
得出结论:常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
参考文:Java类初始化顺序
- Java中的类加载顺序
- Java类加载顺序
- java类加载顺序
- Java类加载顺序
- Java 类加载顺序
- java 类加载顺序
- java类加载顺序
- Java类加载顺序
- java类加载顺序
- Java类加载顺序
- java类加载顺序
- Java类加载顺序
- Java类加载顺序
- java 类加载顺序
- java 类加载顺序
- Java类加载顺序
- 对于Java类加载过程中的顺序问题探究
- Java类中的各种成员的加载顺序
- 工具包【日期类、格式化、Math类】的使用
- 机器学习:算法性能度量之查准率与查全率
- mprop工具修改Android的default.prop使其可调试
- java io流整理
- 改写CNN网络的一些问题解决方法
- Java中的类加载顺序
- Docker vs Docker-machine
- Springboot 常用注解
- 动态规划问题—经典模型
- Ubuntu 设置当前用户sudo免密码
- unity 接入A*寻路算法总结
- SDUT算术表达式的转换(二叉树做法,建树及转换操作)
- 8.7 模拟
- C/C++中关于qsort的使用