这里讲的不是类加载机制,是类的加载先后顺序。话不多说了,先设定以下场景:
package com.jingdong;
public class A {
public static void main(String[] args){
System.out.println(Ib.b);
B b=new B();
b.ibTest();
}
}
public class B implements Ib{
private D d;
private C c=new C();
@Override
public void ibTest() {
// TODO Auto-generated method stub
System.out.println("ibtest hello1");
d=new D();
}
}
public class C implements Ic{
@Override
public void icTest() {
}
}
public class D {
}
public interface Ib {
public static String b="this b ";
public void ibTest();
}
public interface Ic {
public void icTest();
}
执行该程序:java -verbose:class com.jingdong.A
输出如下:
[Loaded com.jingdong.A from file:/F:/myj2ee/j2ee/classTest/src/]
this b
[Loaded com.jingdong.Ib from file:/F:/myj2ee/j2ee/classTest/src/]
[Loaded com.jingdong.B from file:/F:/myj2ee/j2ee/classTest/src/]
[Loaded com.jingdong.Ic from file:/F:/myj2ee/j2ee/classTest/src/]
[Loaded com.jingdong.C from file:/F:/myj2ee/j2ee/classTest/src/]
ibtest hello1
[Loaded com.jingdong.D from file:/F:/myj2ee/j2ee/classTest/src/]
顺序如下:
首先JVM查找main方法,加载到A类
main方法第一句是:System.out.println(Ib.b);输出了:this b
注意此时并没有加载Ib接口,说明:在使用接口的静态变量时是不会加载该接口口的
main方法第二句:B b=new B();输出了:
[Loaded com.jingdong.Ib from file:/F:/myj2ee/j2ee/classTest/src/]
[Loaded com.jingdong.B from file:/F:/myj2ee/j2ee/classTest/src/]
说明加载了B,在加载B时,会优先加载B的超类(父类)和接口.这里有个疑问,到底是表达表B b触发了加载B类还是new B()呢,后面会讲到。
再看后面两句输出:
[Loaded com.jingdong.Ic from file:/F:/myj2ee/j2ee/classTest/src/]
[Loaded com.jingdong.C from file:/F:/myj2ee/j2ee/classTest/src/]
该输出是由于加载B类触发的,因为B类用到了成员变量C,D,但是为什么只加载了C而没有加载D呢。看B的声明:
private D d;
private C c=new C();
这说明:
只是引用一个类时是不会类加载器去加载该类的,只有在需要实例化类或者调用XXX.class时才会去加载。这里只有C被实例化了,因此只会输出加载了Ic和C
最后A类的main方法执行了:b.ibTest();
输出如下:System.out.println("ibtest hello1");
然后再执行语句d=new D();的时候触发了D的加载。
现在我好奇如果我们把d=new D();去掉,在javac以后(即编译以后)是不是就可以把D.class删了呢。
经实验发现这的确是可行的,因为D类一直没有机会实例化,因此可以删除