Javaのimportについて自分なりに整理

そもそもはEclipseで外部ライブラリをimportするのってどうするんですか?という後輩さんの質問に答えられなかったのがきっかけ。 調べ物をしていくうちに、そもそもEclipseなしで外部ライブラリを使うのってスイスイできないなって気づいた。これはまずい。

先に結論を述べて、そのあと実験します。

結論

Javaでクラスファイルをimportするには、以下の2点を守る必要がある 1. コンパイル時のクラスパスに必要なクラスファイル(ないしはソースファイル)があること 2. 実行時のクラスパスに必要なクラスファイルがあること

実験

二つのソースファイルをもつ簡単なプログラムを作って、コンパイル時と実行時に条件を変えて試してみた。

ソースファイル

src/ ├ Hello.java └ spanish/ └ Hola.java

import spanish.Hola;

public class Hello {
    public static void main(String[] args){
        System.out.println("Hello, world.");
        Hola hola = new Hola();
        hola.printHola();
    }
}
package spanish;

public class Hola{
    public void printHola(){
        System.out.println("Hola!!");
    }
}

コンパイル

  • 現在のクラスパス(src/)に、パッケージ名に沿ったディレクトリ構成で外部クラス(Hola.java)が配置されている場合 src/ ├ Hello.java └ spanish/ └ Hola.java
$ javac Hello.java
(エラーなし)
  • 使いたいクラスがパッケージ名に沿って置かれていない場合 src/ ├ Hello.java ├ Spanish/ └ Hola.java
$ javac Hello.java
Hello.java:1: error: package spanish does not exist
import spanish.Hola;
              ^
Hello.java:6: error: cannot access Hola
        Hola hola = new Hola();
        ^
  bad source file: ./Hola.java
    file does not contain class Hola
    Please remove or make sure it appears in the correct subdirectory of the sourcepath.
2 errors

実行時

  • クラスパス(src/)上に外部クラス(Hola.class)がある場合 src/ ├ Hello.java ├ Hello.class └ spanish/ ├ Hola.java └ Hola.class
$ java Hello
Hello, world.
Hola!!
  • クラスパス上にクラス定義がない場合 src/ ├ Hello.java ├ Hello.class └ spanish/ └ Hola.java
$ java Hello
Hello, world.
Exception in thread "main" java.lang.NoClassDefFoundError: spanish/Hola
    at Hello.main(Hello.java:6)
Caused by: java.lang.ClassNotFoundException: spanish.Hola
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more

ソースファイルがあってもダメ。

  • 現在のディレクトリ(src/)にはパッケージはないが、別のディレクトリにパッケージがあり、クラスパスが通っている場合 java/ ├ src/ │ ├ Hello.java │ └ Hello.class ├ another/ └ spanish/ └ Hola.class
$ java -classpath .:../another Hello
Hello, world.
Hola!!

コンパイル時と実行時で、クラスファイルが置いてある場所が違っても構わない!知らなかった!