クラスロードについてもう少し調べてみた

前回の記事と同様に、クラスロードに関してはVM次第な部分があるので、参考程度でお願いします。

前回からさらに

init/createdのログをみてもらうとわかるのだけれど、この時点でClassLoaderSampleがすでにクラスロードされている。
ClassLoaderSampleには、Buzz4を返すメソッドがあるにもかかわらず、Buzz4はロードされておらず、クラスロードされるのは、実際にBuzz4をnewしたときとなっている。
逆にBuzz/Buzz3はClassLoaderSampleがロードされた段階で、ClassLoaderに登録されてしまっている

ようするに

クラスがロードされるときは、自クラスを構成するクラスを全部読み込んでるわけではなく、キャストの必要なものだけがロードされているようだ。
返り値の型とreturn時の型が同じであれば、呼ぶまでは何もロードしていない。

ちなみに

フィールドでも同じ現象が起きるみたい。
また別の機会にでも検証してみようかな

環境

JDK1.6

出力結果

### init     ####
class limelabo.ClassLoaderSample
class limelabo.ClassLoaderSample$Buzz
class limelabo.ClassLoaderSample$Buzz3
#### created  ####
class limelabo.ClassLoaderSample
class limelabo.ClassLoaderSample$Buzz
class limelabo.ClassLoaderSample$Buzz3
#### Buzz3  ####
class limelabo.ClassLoaderSample
class limelabo.ClassLoaderSample$Buzz
class limelabo.ClassLoaderSample$Buzz3
#### Buzz4  ####
class limelabo.ClassLoaderSample
class limelabo.ClassLoaderSample$Buzz
class limelabo.ClassLoaderSample$Buzz3
class limelabo.ClassLoaderSample$Buzz4

ソースコード

package limelabo;

import java.lang.reflect.Field;
import java.util.Vector;

public class ClassLoaderSample {

    public static void main(String[] args) {
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        printClassLoader("### init     ####", cl);
        ClassLoaderSample hoge = new ClassLoaderSample();
        printClassLoader("#### created  ####", cl);
        
        hoge.createBuzz3();
        printClassLoader("#### Buzz3  ####", cl);
        hoge.createBuzz4();
        printClassLoader("#### Buzz4  ####", cl);
        
    }

    private Buzz createBuzz3() {
        return new Buzz3();
    }

    private Buzz4 createBuzz4() {
        return new Buzz4();
    }

    static class Buzz {
    }

    static class Buzz3 extends Buzz {
    }

    static class Buzz4 extends Buzz {
    }

    /**
     * @param message
     * @param cl
     */
    private static void printClassLoader(String message, ClassLoader cl) {
        System.out.println(message);
        Class<?> c = cl.getClass();
        // ClassLoaderまでさかのぼる
        for (; !ClassLoader.class.getName().equals(c.getName()); c = c.getSuperclass()) {
        }
        try {
            Field classesField = c.getDeclaredField("classes");
            classesField.setAccessible(true);
            Vector<Class> classes = (Vector<Class>) classesField.get(cl);
            for (Class loadedClass : classes) {
                System.out.println(loadedClass);
            }
        } catch (Exception e) {
            // とりあえず無視
            e.printStackTrace();
        }
    }
}