用語は正しく覚えよう: システムクラスローダとブートストラップクラスローダ

ディスカッションの最中、どうも話がかみ合わないと思ったら用語の使い方が間違っていた、ということが時々ある。同じ概念を違う用語で呼んでいる場合はすぐに気づくので問題ない*1が、同じ用語で違う概念を指していると混乱の元凶になる。なので、ちょっと面倒ではあるが、正しい用語を1次情報に当たって確認するクセを付けてほしい。
とまあ偉そうなことを書いたが、僕自身、用語を間違って覚えていて相手を混乱させてしまった経験は枚挙に暇がない。今回もまた1つそんなことがあったので、備忘のためにここに書いておく。
間違って覚えていた用語は「システムクラスローダ (system class loader)」。java.lang.ClassLoader#getSystemClassLoader() で取得できるクラスローダのことだが、実は、JVM が内部的に持っているクラスローディング機構((JVM には、ClassLoader オブジェクトを使わずにクラスをロードする特別の仕組みがある。そうでないと、たとえば、「ClassLoader クラスをロードする ClassLoader オブジェクト」といった鶏と卵の問題が生じてしまう。))のことなんだと思っていた。

JVM 自体が備えるクラスローディング機構は「ブートストラップクラスローダ」

実際には、JVM が持つ特別のクラスローディング機構を指す用語は「ブートストラップクラスローダ (bootstrap class loader)」。これは、Java 仮想マシン仕様*2の以下の記述による:

5.3 Creation and Loading
There are two types of class loaders: user-defined class loaders and the bootstrap class loader supplied by the Java virtual machine. Every user-defined class loader is an instance of a subclass of the abstract class ClassLoader.
ブートストラップクラスローダは特別な存在で、Java プログラムからこれにアクセスする手段は存在しない。たとえば、ブートストラップクラスローダによってロードされたクラスの Class#getClassLoader() メソッドを呼び出しても、null が返されてしまう。

結局、「システムクラスローダ」とは何なのか?

では、「システムクラスローダ」というのはいったい何か? 実は、この用語は、Java 仮想マシン仕様にも Java 言語仕様*3にも現れない。ClassLoader#getSystemClassLoader() メソッドの仕様に以下のようにあるだけだ:


Returns the system class loader for delegation. This is the default delegation parent for new ClassLoader instances, and is typically the class loader used to start the application.
そう。「システムクラスローダ」とは、「クラスローダの委譲連鎖におけるデフォルトの親」のことだ。それ以上でもそれ以下でもない。通常は main メソッドのクラスをロードするが、それも「典型的には (typically)」そうなだけで必ずそうであるとは限らない。実際、Java 仮想マシン仕様には以下のような記述もある:
5.2 Virtual Machine Start-up

The Java virtual machine starts up by creating an initial class, which is specified in an implementation-dependent manner, using the bootstrap class loader (§5.3.1). The Java virtual machine then links the initial class, initializes it, and invokes its public class method void main(String[]).《中略》

In some implementations of the Java virtual machine the initial class could be provided as a command line argument, as in JDK releases 1.0 and 1.1. Alternatively, the initial class could be provided by the implementation. In this case the initial class might set up a class loader that would in turn load an application, as in the Java 2 SDK, Standard Edition, v1.2. Other choices of the initial class are possible so long as they are consistent with the specification given in the previous paragraph.

どうやら、JDK 1.0 や 1.1 の頃は main メソッドのクラスをブートストラップクラスローダがロードしていたらしい。
ちなみに、ClassLoader#getSystemClassLoader() メソッドの仕様には、システムクラスローダは好きなクラスに差し替えることができると書いてある:


The default system class loader is an implementation-dependent instance of this class.


If the system property "java.system.class.loader" is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent. An instance is then created using this constructor with the default system class loader as the parameter. The resulting class loader is defined to be the system class loader.

これからすると、「システムクラスローダ」というのは、特定のクラスローダを指す用語ではなく、ある種のクラスローダが占める役割を指す用語だと解釈するのが自然かもしれない。

*1:分からない言葉が出てきたら、その場ですぐに聞き返すクセを付けよう。

*2:『The Java Virtual Machine Specification Second Edition』

*3:『The Java Language Specification, Third Edition』