java遵循“使用时,才加载”的原则。
注意:类的加载过程只发生一次。
1.对于不含静态方法的非抽象类而言,如果你只是创建了一个类的空引用,并没有执行new操作,该类是不会被加载的。也就是说,一个不含静态方法的非抽象类要被加载的话,肯定是在第一次实例化对象时,才会发生类的加载,同时生成实例化对象。但是之后再实例化对象,类的加载过程不会再发生,类的加载过程只发生一次。
2.对于含静态方法的非抽象类而言,第一次执行new操作进行实例化或者调用类方法(即该类的静态方法)时,该类才会被加载的。
3.对于不含静态方法的抽象类而言,只有继承了该类的非抽象子类要被加载时,该不含静态方法的抽象类才会被加载。且抽象父类先加载,非抽象子类后加载。至于非抽象子类什么时候会被加载,见1、2两点。
4.对于含静态方法的抽象类而言,继承了该类的非抽象子类要被加载时或者调用该含静态方法的抽象类的类方法(即该类的静态方法)时,该含静态方法的抽象类才会被加载。
5.接口和不含静态方法的抽象类情况类似,都是只有继承了该接口的非抽象子类要被加载时,该接口才会被加载。应该是父接口先加载,非抽象子类后加载。
上面列了五段话说的绕来绕去的(感觉基础不好的真的会被绕晕,我自己都觉得绕),其实就是为了说明开头的那一段话“java遵循“使用时,才加载”的原则”。通俗点说就是只有用得着某个类或接口的时候,这个类或接口才会被加载,否则就是哪凉快哪待着去。
下面给出相应的测试代码(比较长,但很细致):
//类A在这里只是为了提供主方法,我们不用把问题搞太复杂了。此处不考虑类A的加载问题
class TestMain{
public static void main(String[] args) {
System.out.println("类A的主方法执行");
System.out.println("先看第1点");
One one1;
System.out.println("已经定义了类One的空引用,但由于类One没有被加载,所以上一行没有‘类One被加载了’的字样");
System.out.println("下面要通过实例化类One来触发类One的加载了:");
new One();
System.out.println("第1点被验证完毕");
System.out.println("###############我是快乐的分割线##############");
System.out.println();
System.out.println("再看第2点");
System.out.println("下面要通过实例化类TwoFirst来触发类TwoFirst的加载了:");
new TwoFirst();
System.out.println("或者通过调用类TwoSecond的类方法来触发类TwoSecond的加载了:");
TwoSecond.two();
System.out.println("第2点被验证完毕");
System.out.println("###############我是快乐的分割线##############");
System.out.println();
System.out.println("再看第3点");
System.out.println("下面要通过实例化类ThreeSon来触发类Three的加载了:");
new ThreeSon();
System.out.println("以上结果可以看出实例化类ThreeSon触发了类Three的加载,且Three先加载,ThreeSon后加载");
System.out.println("第3点被验证完毕");
System.out.println("###############我是快乐的分割线##############");
System.out.println();
System.out.println("再看第4点");
System.out.println("下面要通过实例化类FourFirstSon来触发类FourFirst的加载了:");
new FourFirstSon();
System.out.println("以上结果可以看出实例化类FourFirstSon触发了类FourFirst的加载,且FourFirst先加载,FourFirstSon后加载");
System.out.println("或者通过调用类FourSecond的类方法来触发类FourSecond的加载了:");
FourSecond.four();
System.out.println("第4点被验证完毕");
System.out.println("###############我是快乐的分割线##############");
System.out.println();
System.out.println("再看第5点");
System.out.println("下面要通过实例化类FiveSon来触发接口Five的加载了:");
new FiveSon();
System.out.println("以上结果可以看出实例化类FiveSon触发了接口Five的加载,且接口Five先加载,FiveSon后加载");
System.out.println("第5点被验证完毕");
System.out.println("###############我是快乐的分割线##############");
}
}
//类One就是第1点所说的不含静态方法的非抽象类,注意不要把静态方法和静态代码块搞混淆了。
class One{
// 静态代码块会随着类的加载而执行,所以可以反映所在类的加载情况
static {
System.out.println("类One被加载了");
}
void one() {
System.out.println("类One的非静态成员方法执行");
}
}
//类TwoFirst和TwoSecond就是第2点所说的含静态方法的非抽象类,注意不要把静态方法和静态代码块搞混淆了。
class TwoFirst{
// 静态代码块会随着类的加载而执行,所以可以反映所在类的加载情况
static {
System.out.println("类TwoFirst被加载了");
}
static void two() {
System.out.println("类TwoFirst的类方法执行");
}
}
class TwoSecond{
// 静态代码块会随着类的加载而执行,所以可以反映所在类的加载情况
static {
System.out.println("类TwoSecond被加载了");
}
static void two() {
System.out.println("类TwoSecond的类方法执行");
}
}
//类Three就是第3点所说的不含静态方法的抽象类,ThreeSon是它的非抽象子类
abstract class Three{
static {
System.out.println("抽象类Three加载");
}
void three() {
System.out.println("抽象类Three类方法执行");
};
}
class ThreeSon extends Three{
static {
System.out.println("ThreeSon被加载了");
}
}
//类FourFirst、FourSecond就是第4点所说的含静态方法的抽象类,类FourFirstSon是类FourFirst的非抽象子类
abstract class FourFirst{
static {
System.out.println("抽象类FourFirst加载");
}
static void four() {
System.out.println("抽象类FourFirst类方法执行");
};
}
class FourFirstSon extends FourFirst{
static {
System.out.println("FourFirstSon被加载了");
}
}
abstract class FourSecond{
static {
System.out.println("抽象类FourSecond加载");
}
static void four() {
System.out.println("抽象类FourSecond类方法执行");
};
}
//Five是第5点提到的接口,FiveSon是它的非抽象子类
interface Five {
String string = "侧面印证接口的加载";
}
class FiveSon implements Five{
static {
System.out.println(string);
System.out.println("FiveSon被加载了");
}
}
其实关于接口的加载验证的不是很严谨,但这里先不计较了。下面是运行结果:
类A的主方法执行
先看第1点
已经定义了类One的空引用,但由于类One没有被加载,所以上一行没有‘类One被加载了’的字样
下面要通过实例化类One来触发类One的加载了:
类One被加载了
第1点被验证完毕
###############我是快乐的分割线##############
再看第2点
下面要通过实例化类TwoFirst来触发类TwoFirst的加载了:
类TwoFirst被加载了
或者通过调用类TwoSecond的类方法来触发类TwoSecond的加载了:
类TwoSecond被加载了
类TwoSecond的类方法执行
第2点被验证完毕
###############我是快乐的分割线##############
再看第3点
下面要通过实例化类ThreeSon来触发类Three的加载了:
抽象类Three加载
ThreeSon被加载了
以上结果可以看出实例化类ThreeSon触发了类Three的加载,且Three先加载,ThreeSon后加载
第3点被验证完毕
###############我是快乐的分割线##############
再看第4点
下面要通过实例化类FourFirstSon来触发类FourFirst的加载了:
抽象类FourFirst加载
FourFirstSon被加载了
以上结果可以看出实例化类FourFirstSon触发了类FourFirst的加载,且FourFirst先加载,FourFirstSon后加载
或者通过调用类FourSecond的类方法来触发类FourSecond的加载了:
抽象类FourSecond加载
抽象类FourSecond类方法执行
第4点被验证完毕
###############我是快乐的分割线##############
再看第5点
下面要通过实例化类FiveSon来触发接口Five的加载了:
侧面印证接口的加载
FiveSon被加载了
以上结果可以看出实例化类FiveSon触发了接口Five的加载,且接口Five先加载,FiveSon后加载
第5点被验证完毕
###############我是快乐的分割线##############