トップ 一覧 検索 ヘルプ RSS ログイン

技術的雑談-Javaコンパイラ・ソースの基礎の変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!!!技術的雑談-Javaコンパイラ・ソースの基礎

!!環境
*JDK1.4、1.5どっちも。
*プラットフォーム問わず

!!目的
何でJavaのソースはあんなにディレクトリがたくさんあるのか理解する

!!内容

Javaではソースについて以下の3つのお約束があります。

+ ソースファイルは「*.java」、コンパイルされたファイル(classファイル)は「*.class」
+ 基本的に、ソースのファイル名と中のClass名は同じにする。
+ ソースの置いてあるディレクトリ階層はClassのPackage階層に合わせる

(ルール3は別に守らなくてもコンパイルは可能ですが、著しくめんどくさくなります。)

ソース、クラス(コンパイルした後の生成物)はpackage(C++で言うところのNamespace)ごとにディレクトリが掘られるのが普通です。

例えば、以下のようなソース構成だったとします。

 [ディレクトリ]
 ./
     /src
         /com
             /hoge
                 /fuga
                     TestClass.java
                 /mugyo
                     Sub.java
     /bin

 [TestClass.java]
 package com.hoge.fuga;
 
 public class TestClass {
 
 }

 [Sub.java]
 package com.hoge.mugyo;
 
 // SubはTestClassを参照している
 public class Sub extends com.hoge.fuga.TestClass {
 
 }

この状態で「TestClass」に対して下記のようにjavacを実行すると、

 (./ ディレクトリにいる)
 javac -sourcepath ./src -d ./bin ./src/com/hoge/fuga/TestClass.java

 [ディレクトリ]
 ./
     /src
         /com
             /hoge
                 /fuga
                     TestClass.java
                 /mugyo
                     Sub.java
     /bin
         /com
             /hoge
                 /fuga
                     TestClass.class

というファイルが作られます。
ディレクトリはコンパイラによって勝手に作られます。

javacコンパイラはコンパイルに必要な依存Classを以下の方法で探してきます。

- 指定されているソースツリー(-sourcepathで示されるディレクトリ以下)
- javacに-classpathで指定されているjar、もしくはディレクトリ
- JDK標準ライブラリー (普通は${JAVA_HOME}/jre/lib以下のjar)

先程生成されたTestClass.classを消して、

 javac -sourcepath ./src -d ./bin ./src/com/hoge/mugyo/Sub.java

を実行しても、

 [ディレクトリ]
 ./
     /src
         /com
             /hoge
                 /fuga
                     TestClass.java
                 /mugyo
                     Sub.java
     /bin
         /com
             /hoge
                 /fuga
                     TestClass.class
                 /mugyo
                     Sub.class

と、Sub.classだけでなくTestClass.classも作られます。

これは -sourcepath ./srcが指定されているのでコンパイラが自動的にpackage構造を理解して必要なClassを探してくる為です。
その過程でコンパイラはTestClassも依存性があると判断して勝手にコンパイルします。

また、./src/com/hoge/fuga/TestClass.javaがない状態でも、./bin/com/hoge/fuga/TestClass.classがあるなら、

 javac -sourcepath ./src -d ./bin -classpath ./bin com/hoge/mugyo/Sub.java

と実行する事により、コンパイラがSub.javaが依存するコンパイル済みのTestClass.classを探してきて、コンパイルを完了します。

上記からもわかるように、-sourcepath、-classpathはその下にあるpackage階層をディレクトリ階層によって理解しますので、ソースもclassもpackageの階層どおりに掘っておく事が望ましいです。

実際は、1つ1つ指定すればソースは階層を無視した状態(例えば、全てのpackageのソースを1つのディレクトリにフラットに置くとか)でもコンパイルは通ります。
しかし、Class毎の依存関係をコンパイラが自動的に判断できない為、ものすごく面倒になります。
(人間が人力で依存関係を解析して、-classpathに与えてやる必要があります。)

!!履歴
2005/7/15 -- 初版発行

[[技術的雑談]]に戻る

!!突っ込み
{{comment}}

[[技術的雑談]]に戻る

{{trackback}}

[[技術的雑談]]へ戻る