トップに戻る

フォルダ分けから学ぶ package と import

Javaの学習用の教材ページです。

1

v1:同じフォルダに4ファイルを作る

4ファイルすべてに package 宣言を書きません。同じ無名パッケージに属するので、別ファイルのクラスも import なしで名前を使えます。

保存するフォルダ構成

09-v1
09-v1javac / java の実行場所
  • Ape.java
  • Human.java
  • HealthCalculator.java
  • Main.java

コードを保存したら、ここで実行

コマンドの実行場所

Windows のコマンドプロンプトを pro3 フォルダで開き、次の3行を順に実行します。JDK の javac・java が使える環境が前提です。ファイルは UTF-8 で保存します。

1. フォルダへ移動
cd 09-v1
2. コンパイル
javac -encoding UTF-8 *.java
3. 実行
java Main

4つの .java があるフォルダでコンパイルします。実行には拡張子なしのクラス名 Main を指定します。

Ape.java

コードの配色
全文
public class Ape {
    private String name;

    public Ape(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + "が食事をします。");
    }
}

Human.java

コードの配色
全文
public class Human extends Ape {
    private double heightCm;
    private double weightKg;

    public Human(String name, double heightCm, double weightKg) {
        super(name);
        this.heightCm = heightCm;
        this.weightKg = weightKg;
    }

    public double getHeightCm() {
        return heightCm;
    }

    public double getWeightKg() {
        return weightKg;
    }
}

HealthCalculator.java

コードの配色
全文
public class HealthCalculator {
    public double calculateBmi(double heightCm, double weightKg) {
        double heightM = heightCm / 100.0;
        return weightKg / (heightM * heightM);
    }
}

Main.java

コードの配色
全文
public class Main {
    public static void main(String[] args) {
        Human taro = new Human("太郎", 170, 65);
        Human hanako = new Human("花子", 160, 50);
        HealthCalculator calculator = new HealthCalculator();

        taro.eat();
        double taroBmi = calculator.calculateBmi(taro.getHeightCm(), taro.getWeightKg());
        System.out.printf("太郎のBMI: %.1f%n", taroBmi);
        System.out.println("=====");

        hanako.eat();
        double hanakoBmi = calculator.calculateBmi(hanako.getHeightCm(), hanako.getWeightKg());
        System.out.printf("花子のBMI: %.1f%n", hanakoBmi);
        System.out.println("=====");
    }
}

表示結果

v1
太郎が食事をします。
太郎のBMI: 22.5
=====
花子が食事をします。
花子のBMI: 19.5
=====

taro.eat()hanako.eat() は Ape から継承したメソッドです。BMI は身長を m に直し、体重 ÷ 身長 ÷ 身長で計算しています。

同じフォルダに置いたから自動で継承されるわけではありません。Human extends Ape と明示して継承し、super(name) で Ape のコンストラクタを呼び出します。

2

v2:フォルダを分け、import なしで使う

09-v1 を残して、新しく 09-v2 を作ります。役割ごとのフォルダにクラスを置き、package で所属先を宣言します。ここでは import を使わず、別パッケージのクラスを「パッケージ名.クラス名」という完全修飾名で指定します。

保存するフォルダ構成

09-v2
09-v2javac / java の実行場所
  • speciespackage species
    • Ape.java
  • livingthingspackage livingthings
    • Human.java
  • calculatorpackage calculator
    • HealthCalculator.java
  • mainpackage main
    • Main.java

コードを保存したら、ここで実行

コマンドの実行場所

Windows のコマンドプロンプトを pro3 フォルダで開き、次の3行を順に実行します。JDK の javac・java が使える環境が前提です。ファイルは UTF-8 で保存します。

1. フォルダへ移動
cd 09-v2
2. コンパイル
javac -encoding UTF-8 main\Main.java livingthings\Human.java species\Ape.java calculator\HealthCalculator.java
3. 実行
java main.Main

main フォルダの中には移動しません。4つのフォルダを含む 09-v2 が実行の基準です。java main.Main のドットはパッケージ名とクラス名の区切りです。

species/Ape.java

コードの配色
青・赤文字がv1から追加した文字
package species;

public class Ape {
    private String name;

    public Ape(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + "が食事をします。");
    }
}

livingthings/Human.java

コードの配色
青・赤文字がv1から追加した文字
package livingthings;

public class Human extends species.Ape {
    private double heightCm;
    private double weightKg;

    public Human(String name, double heightCm, double weightKg) {
        super(name);
        this.heightCm = heightCm;
        this.weightKg = weightKg;
    }

    public double getHeightCm() {
        return heightCm;
    }

    public double getWeightKg() {
        return weightKg;
    }
}

calculator/HealthCalculator.java

コードの配色
青・赤文字がv1から追加した文字
package calculator;

public class HealthCalculator {
    public double calculateBmi(double heightCm, double weightKg) {
        double heightM = heightCm / 100.0;
        return weightKg / (heightM * heightM);
    }
}

main/Main.java

コードの配色
青・赤文字がv1から追加した文字
package main;

public class Main {
    public static void main(String[] args) {
        livingthings.Human taro = new livingthings.Human("太郎", 170, 65);
        livingthings.Human hanako = new livingthings.Human("花子", 160, 50);
        calculator.HealthCalculator calculator = new calculator.HealthCalculator();

        taro.eat();
        double taroBmi = calculator.calculateBmi(taro.getHeightCm(), taro.getWeightKg());
        System.out.printf("太郎のBMI: %.1f%n", taroBmi);
        System.out.println("=====");

        hanako.eat();
        double hanakoBmi = calculator.calculateBmi(hanako.getHeightCm(), hanako.getWeightKg());
        System.out.printf("花子のBMI: %.1f%n", hanakoBmi);
        System.out.println("=====");
    }
}

表示結果

v2
太郎が食事をします。
太郎のBMI: 22.5
=====
花子が食事をします。
花子のBMI: 19.5
=====

taro.eat()hanako.eat() は Ape から継承したメソッドです。BMI は身長を m に直し、体重 ÷ 身長 ÷ 身長で計算しています。

この例ではフォルダ名をパッケージ名に合わせています。クラス名とフォルダ名は同じでなくて構いません。別パッケージから使うクラス・コンストラクタ・メソッドには public を付けています。

完全修飾名は「所属先まで含めたクラス名」

livingthings.Human は livingthings パッケージの Human です。変数の型にも、new の後にも完全な名前を書きます。extends species.Ape も同じ考え方です。

calculator.HealthCalculator calculator の左側は型、右側の calculator は変数名です。先頭の calculator はパッケージ名を表します。

import がなくても、所属先を含む名前でクラスを使えます。フォルダ分けのための package と、名前を短くする import は別の役割です。

3

v3:import でクラス名を短く書く

09-v2 をコピーして 09-v3 を作ります。フォルダ構成と package はそのままで、Human.java と Main.java に import を追加し、完全修飾名を短いクラス名に置き換えます。表示結果は v2 と同じです。

保存するフォルダ構成

09-v3
09-v3javac / java の実行場所
  • speciespackage species
    • Ape.java
  • livingthingspackage livingthings
    • Human.java
  • calculatorpackage calculator
    • HealthCalculator.java
  • mainpackage main
    • Main.java

コードを保存したら、ここで実行

コマンドの実行場所

Windows のコマンドプロンプトを pro3 フォルダで開き、次の3行を順に実行します。JDK の javac・java が使える環境が前提です。ファイルは UTF-8 で保存します。

1. フォルダへ移動
cd 09-v3
2. コンパイル
javac -encoding UTF-8 main\Main.java livingthings\Human.java species\Ape.java calculator\HealthCalculator.java
3. 実行
java main.Main

main フォルダの中には移動しません。4つのフォルダを含む 09-v3 が実行の基準です。java main.Main のドットはパッケージ名とクラス名の区切りです。

species/Ape.java

コードの配色
青文字がv2から追加した文字
package species;

public class Ape {
    private String name;

    public Ape(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + "が食事をします。");
    }
}

livingthings/Human.java

コードの配色
青文字がv2から追加した文字
package livingthings;

import species.Ape;

public class Human extends Ape {
    private double heightCm;
    private double weightKg;

    public Human(String name, double heightCm, double weightKg) {
        super(name);
        this.heightCm = heightCm;
        this.weightKg = weightKg;
    }

    public double getHeightCm() {
        return heightCm;
    }

    public double getWeightKg() {
        return weightKg;
    }
}

calculator/HealthCalculator.java

コードの配色
青文字がv2から追加した文字
package calculator;

public class HealthCalculator {
    public double calculateBmi(double heightCm, double weightKg) {
        double heightM = heightCm / 100.0;
        return weightKg / (heightM * heightM);
    }
}

main/Main.java

コードの配色
青文字がv2から追加した文字
package main;

import livingthings.Human;
import calculator.HealthCalculator;

public class Main {
    public static void main(String[] args) {
        Human taro = new Human("太郎", 170, 65);
        Human hanako = new Human("花子", 160, 50);
        HealthCalculator calculator = new HealthCalculator();

        taro.eat();
        double taroBmi = calculator.calculateBmi(taro.getHeightCm(), taro.getWeightKg());
        System.out.printf("太郎のBMI: %.1f%n", taroBmi);
        System.out.println("=====");

        hanako.eat();
        double hanakoBmi = calculator.calculateBmi(hanako.getHeightCm(), hanako.getWeightKg());
        System.out.printf("花子のBMI: %.1f%n", hanakoBmi);
        System.out.println("=====");
    }
}

表示結果

v3
太郎が食事をします。
太郎のBMI: 22.5
=====
花子が食事をします。
花子のBMI: 19.5
=====

taro.eat()hanako.eat() は Ape から継承したメソッドです。BMI は身長を m に直し、体重 ÷ 身長 ÷ 身長で計算しています。

この例ではフォルダ名をパッケージ名に合わせています。クラス名とフォルダ名は同じでなくて構いません。別パッケージから使うクラス・コンストラクタ・メソッドには public を付けています。

v2 → v3:所属先は同じ、参照する名前を短くする

v2:完全修飾名v3:import 後
extends species.Apeextends Ape
livingthings.HumanHuman
calculator.HealthCalculatorHealthCalculator

import はファイルごとに書きます。Human.java では species.Ape、Main.java では livingthings.Human と calculator.HealthCalculator を指定します。Main.java から Ape を直接使っていないので、Ape の import は不要です。

import を追加してもクラスの所属先は変わりません。v2・v3 ともに、実行するクラス名は main.Main です。コマンドは、それぞれの 09-v2・09-v3 フォルダで実行します。

4. package・import・extends・new を整理する

やさしく言うと

所属先とショートカット
1

package:私の住所はここですよ

package livingthings; は「私は livingthings に所属しています」という宣言です。他のパッケージからは livingthings.Human という名前で参照できます。

「私のことを他のフォルダから使ってもいいですよ」に近い役割は public です。package は所属先、public は公開範囲を決めます。

2

import:何回も長い名前を書くのは面倒だから、先頭でショートカットを作ろう

コード内で何回も hoge.huga. のようなパッケージ名を書く代わりに、先頭で使うクラスを指定します。例えば import livingthings.Human; と書けば、そのファイルでは livingthings.HumanHuman と短く書けます。

それぞれの役割

役割の違い
書き方役割
package livingthings;このクラスの所属先を宣言します。コメントを除いて、import やクラス宣言より前に書きます。
import species.Ape;別パッケージの species.Ape を、Ape と短く書けるようにします。継承する働きはありません。
Human extends ApeHuman が Ape の機能を継承します。「人間は類人猿の一種」という関係を表します。
new HealthCalculator()計算機の実体(インスタンス)を作ります。Main は計算機を作って使っています。

import を書かず、public class Human extends species.Ape と完全な名前で指定することもできます。import はフォルダを読み込んだり、ファイルをコピーしたりする命令ではありません。

v1 の「package も import も不要」は、全ファイルに package 宣言がなく、同じ無名パッケージに属する前提です。

実行時に指定する名前が変わる

javac → java

v1:09-v1 で実行

java Main
パッケージ名なしのクラス名

v2・v3:それぞれ 09-v2・09-v3 で実行

java main.Main
パッケージ名を含むクラス名

javac は .java ファイルから .class ファイルを作ります。この例の java コマンドでは .java や .class、フォルダの区切り文字ではなく、クラス名を指定します。現在のフォルダがクラスパスに含まれる通常の環境を想定しています。CLASSPATH を設定している場合は java -cp . Main または java -cp . main.Main と指定できます。