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 (エラーなし)
$ 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!!
$ 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!!
コンパイル時と実行時で、クラスファイルが置いてある場所が違っても構わない!知らなかった!