Java 応用編 3日目

ここでは、オブジェクト指向の三大要素のうちのカプセル化について説明します

パッケージ

パッケージとは、クラスやインターフェースなどのファイルをグループ化して管理する仕組みのことです
パッケージを使うことで、以下のようなメリットがあります

  1. 名前の衝突を回避できる
    同じ名前のクラスでも、異なるパッケージに所属していれば区別できます
    これにより、クラス名の衝突を気にせずに開発を進めることができます
  2. コードの可読性・保守性が向上する
    関連するクラスをまとめてパッケージにすることで、コードの構造が整理され、可読性や保守性が向上します
  3. アクセス制限を設けられる
    パッケージ単位でクラスの可視性を制御できます
    これにより、外部に公開したくないクラスを隠蔽したり、特定のクラスからのアクセスのみを許可したりすることができます
  4. 再利用性が高まる
    パッケージとしてまとめることで、他のプロジェクトや開発者との間でコードを共有しやすくなります

パッケージの作成

パッケージを作成するには、ファイルの先頭にpackage文を記述します

例えば、pkgAというパッケージを作る場合は、以下のように記述します

package pkgA;

同一ファイル内にあるすべてのクラスがこのパッケージに分類されます

パッケージは階層化することもできます
階層化するには、.(ピリオド)でパッケージ名をつなげます

例えば、pkgAパッケージの中にpkgBというパッケージを作る場合は、以下のように記述します

package pkgA.pkgB;

importの宣言

パッケージに属するクラスを使うには、import文を使ってパッケージ名とクラス名を指定します

例えば、pkgAパッケージのPkgTestAクラスを使う場合は、以下のように記述します

import pkgA.PkgTestA;

import文には*を使って、パッケージ内のすべてのクラスを一括で指定することもできます
例えば、pkgAパッケージ内のすべてのクラスを使う場合は、以下のように記述します

import pkgA.*;

また、パッケージはディレクトリ構造に対応しています
たとえば、下図のようなフォルダ構成の場合のサンプルプログラムを提示します

・src\pkgA\pkgB\PkgTestB.java

package pkgA.pkgB;
public class PkgTestB {
   public void test(){
       System.out.println("in PkgTestB()");
   }
}

・src\pkgA\PkgTestA.java

package pkgA;
public class PkgTestA {
   public void test(){
     System.out.println("in PkgTestA()");
   }
}

・src\PkgTest1.java

import pkgA.PkgTestA;
import pkgA.pkgB.PkgTestB;
public class PkgTest1 {
  public static void main(String[] args) {
    PkgTestA a = new PkgTestA();
    PkgTestB b = new PkgTestB();
    a.test();
    b.test();
  }
}
実行結果
in PkgTestA()
in PkgTestB()

Javaのパッケージ例

Javaのパッケージの例を3つ示します

  1. java.langパッケージ
    Javaの基本的なクラスやインターフェースが入っているパッケージです
    例えば、StringObjectMathなどがあります
    このパッケージは自動的にインポートされるので、明示的に書く必要はありません
  2. java.utilパッケージ
    Javaのユーティリティクラスやインターフェースが入っているパッケージです
    例えば、ListMapScannerなどがあります
    このパッケージは自動的にインポートされないので、使うときは明示的に書く必要があります
  3. javax.swingパッケージ
    JavaのGUIコンポーネントやイベントハンドラが入っているパッケージです
    例えば、JFrameJButtonActionListenerなどがあります
    このパッケージも自動的にインポートされないので、使うときは明示的に書く必要があります

カプセル化

クラスの内部のデータを保護するため、外部からのアクセスを制限する概念をカプセル化といいます

クラスの利用者は、公開されているメソッドにアクセスすることで、クラスの機能を利用することができます
カプセル化により、クラスの利用者は内部の構造を理解しなくてもクラスの機能を利用することができたり、外部からの間違ったアクセスを未然に防ぐことができます
Javaでは、public、protected、privateなどのアクセス修飾子やstatic修飾子、final修飾子を指定して実現します

アクセス修飾子

アクセス修飾子は、クラスやメンバー、関数などを、どの範囲から参照可能かを制御するのに用いられます
クラス、インタフェース、メソッド、コンストラクタ、メンバ変数の修飾子として利用できます
アクセス修飾子の一覧は次の通りです

アクセス修飾子 呼び名 意味・機能
public パブリック ほかのどのクラスからでも呼び出せる
protected プロテクティッド サブクラスまたは同じパッケージ内のクラスからしか呼び出せない
なし デフォルト 同じパッケージ内からしか呼び出せない
private プライベート 同じクラス内からしか呼び出せない

public公開範囲

protected公開範囲

デフォルト公開範囲

private公開範囲

Java基礎編7日目で提示したPersonクラスの変数をカプセル化したサンプルプログラムを以下に示します

package sample;

// ⼈クラス
class Person {
    // クラスで使⽤するデータの「名前」と「年齢」をフィールドとして定義する
    // 同⼀クラス内でのみアクセス可能
    private String name;
    private int age;
 
    // コンストラクタ(引数つき)
    Person (String name, int age) {
        this.name = name;
        this.age = age;
    }

    // name変数のセッター⇒外部から値を書き込むための関数
    public void setName(String name) {
        this.name = name;
    }

    // age変数のセッター⇒外部から値を書き込むための関数
    public void setAge(int age) {
        this.age = age;
    }

    // name変数のゲッター⇒外部から値を取得するための関数
    public String getName() {
        return this.name;
    }

    // age変数のゲッター⇒外部から値を取得するための関数
    public int getAge() {
        return this.age;
    }

    // ⾃⼰紹介をするメソッド
    public void introduce () {
        System.out.println ("私の名前は" + name + "です。" + age + "歳です。");
    }
 }
public class Sample{
     
    public static void main(String[] args) {
    // ⼈クラスのインスタンスを⽣成する
        Person person = new Person ();
        person.setName("⼭⽥太郎");
        person.setAge(20);
        System.out.println ("私の名前は" + person.getName() + "です。" + person.getAge() +"歳です。");
        person.introduce();
    }
}
実⾏結果
私の名前は⼭⽥太郎です。20歳です。
私の名前は⼭⽥太郎です。20歳です。

このサンプルプログラムでは、フィールドの変数をprivateとして定義しています

    private String name;
    private int age;

privateと宣言しているため、クラス外からは直接アクセスすることはできません
外部からこのクラスのname、ageに値をセットする関数、値を取得する関数をpublicで用意しています
もし、ageを直接変更できるようにすると、1000などと年齢とはほど遠い値も入ってしまいます
しかし、setAge関数内で範囲外の値のときはエラーを返すなどとしておけば、間違った値の代入を防ぐことができ、データを保護することができるようになります

static修飾子

static修飾⼦は静的メンバーを定義する修飾⼦のことで、メソッド、フィールドに付加することができます
staticで修飾されたフィールドをクラス変数、メソッドをクラス(または静的)メソッドと呼びます
⼀⽅、staticが付加されない場合は、インスタンス変数、インスタンスメソッドと呼びます
クラス変数、クラスメソッドはクラスのインスタンスを⽣成しなくても呼び出すことが出来るという特徴があります

以下にサンプルプログラムを示します

上の図は、以下のサンプルプログラムのクラス変数、クラスメソッド、インスタンス変数、インスタンスメソッドについて説明しています

class Test{
    static int staticNum = 0;  // クラス変数⇒static領域に保存され共有される
    int num=0; // インスタンス変数⇒インスタンスが生成されたときヒープ領域に保存される
}
public class Sample{
    public static void main(String[] args){
        System.out.println("staticNum=" + Test.staticNum);

        Test t1 = new Test();
        t1.num = 1;
        t1.staticNum = 1;

        Test t2 = new Test();
        t2.num = 2;
        t1.staticNum = 2;

        System.out.println("t1.num=" + t1.num);
        System.out.println("t2.num=" + t2.num);
        System.out.println("t1.staticNum=" + t1.staticNum);
        System.out.println("t2.staticNum=" + t2.staticNum);
        System.out.println("Test.staticNum=" + Test.staticNum);
    }
}
実行結果
staticNum=0
t1.num=1
t2.num=2
t1.staticNum=2
t2.staticNum=2
Test.staticNum=2
System.out.println("staticNum=" + Test.staticNum);

クラス変数のため、staticNumはクラス名.変数名でアクセス可能です

一方インスタンス変数はクラス名.変数名でアクセスできないため

System.out.println("staticNum=" + Test.num);

このように記述するとエラーになります

t1.num = 1;
t2.num = 2;

それぞれのインスタンス変数に値を代入しているため、値は異なります

一方、

t1.staticNum = 1;
t1.staticNum = 2;
System.out.println("t1.staticNum=" + t1.staticNum);
System.out.println("t2.staticNum=" + t2.staticNum);
System.out.println("Test.staticNum=" + Test.staticNum);

static領域にあるため共有され、最後に代入した値が表示されます

以下は、インスタンスメソッドとクラスメソッドを使用したサンプルプログラムです

class Test{
    private int num=0;
    
    public static int add(int a,int b){ // クラスメソッドの定義
        return a+b;
    }
    
    public int getNum(){ // インスタンスメソッドの定義
        return num;
    }
}
public class Sample{
    public static void main(String[] args){
        int x;
        x = Test.add(1,2);
        System.out.println("add="+x);
        // x = Test.getnum(); // コンパイルエラーになる
        
        Test t = new Test();
        x = t.getNum();
        System.out.println("getnum="+x);
    }
}
実行結果
add=3
getnum=0

クラスメソッドは、クラス変数同様にクラス名.メソッド名でアクセスします

final修飾子

final修飾子は、後から変更してはいけないものに付加します
クラス、メソッド、フィールドそれぞれに付加した場合のふるまいは次のとおりです

クラス サブクラスが作成できない
メソッド サブクラスでオーバーライドできない
フィールド 値を変更できない

クラスにfinal修飾子を付加したサンプルプログラムです

  • クラスの継承が禁止されている例
final class Test{
    private int num=0;
    
    public int getNum(){
        return num;
    }
}
class Test1 extends Test{
    public int getNum(){
        return super.getNum();
    }
}
public class Sample{
    public static void main(String[] args){
        int x;
        Test t = new Test();
        x = t.getNum();
        System.out.println("getnum="+x);
    }
}
実行結果
Sample.java:9: error: cannot inherit from final Test
class Test1 extends Test{
                    ^
1 error

  • メソッドのオーバーライドが禁止されている例
class Test{
    private int num=0;
    
    public final int getNum(){
        return num;
    }
}

class Test1 extends Test{
    public int getNum(){
        return super.getNum();
    }
}

public class Sample{
    public static void main(String[] args){
        int x;
        Test t = new Test();
        x = t.getNum();
        System.out.println("getnum="+x);
    }
}
実行結果
Sample.java:11: error: getNum() in Test1 cannot override getNum() in Test
    public int getNum(){
               ^
  overridden method is final
1 error

  • フィールドの値の変更が禁止されている例
class Test{
    public static final double PI=3.14;
    double r;
    
    Test(double r){
        this.r = r;
    }
    double getArea(){
        return this.r * this.r * this.PI;
    }
}
public class Sample{
    public static void main(String[] args){
        double x;
        Test t = new Test(2);
        Test.PI=3.5;
        x = t.getArea();
        System.out.println("area="+x);
    }
}
実行結果
Sample.java:20: error: cannot assign a value to static final variable PI
        Test.PI=3.5;
            ^
1 error

上記のようにフィールドの値を変更できないようにしたフィールドのことを定数といいます
定数は、一般的に英大文字で表します

コメント

この記事へのコメントはありません。

関連記事

Java 基本編 4日目

C言語 応用編 ~6日目~

C言語(応用編)演習問題

PAGE TOP