目次へ戻る 下へ↓
10、メンバーとアクセス制御
作成者:Fumitaka Makino 更新日:2003-04-08 11:48

・メンバーとは?

Javaの文献などを見ているとよく「メンバー」という単語がでてきますね。このメンバーとはいったいなんでしょうか?メンバーと言うのはクラスを構成するメソッドやクラス変数(メソッドと同じレベルにある変数、フィールドと言う)のことを表します。例えば以下のクラスの場合は変数nameとsetName、getNameメソッドがメンバーに相当します。

例:メンバーの説明のためのサンプル

     
 
/**
  Javaにおけるメンバーの説明のためのサンプル
*/
public class MemberSample {
  

  
  /**
    プライベートなStringフィールド
  */
  private String name = null;
  
  

  /**
    名前をセットするためのパブリックなメソッド
  */
  public void setName( String sname ){
    this.name = sname;
  }
  
  

  /**
    名前を取得するためのパブリックなメソッド
  */
  public String getName(){
    return this.name;
  }

  
}

 
     

そして、通常はメンバーはフィールド、メソッドと言う形で呼ばれます。またメンバーにはこのあと説明するアクセス権限というものが設けてあり、クラス外部からの呼び出しをコントロールしています。

 

・パッケージとは?

パッケージは既にいたるところで出現していますね。java.lang.Object、java.util.Vectorなどでいわれるがままかもしれませんが、パッケージを利用しています。ちなみに、ObjectやVectorの場合は

java.lang.Object → java.langパッケージのObjectクラス
java.util.Vector → java.utilパッケージのVectorクラス

と解釈されます。なぜパッケージなしのVectorやObjectではいけないのでしょうか?なぜわざわざパッケージをいくつも作るのでしょうか。それには下記のように理由があります。

  1. 用途や特定の約束事により、クラスを区分けすることができる。
  2. あるクラスを特定するのがクラス名だけではクラス名の衝突が起こるため、パッケージを利用することにより衝突を避ける。
  3. パッケージはアクセス制御の単位として利用できる。

1の場合は単純に便利だからです。役割や所属の違うファイルを同じ場所に一箇所に集めておくと整理ができず不便ですね?それと同じです。2の場合を考えてみましょう、例えば2つの組織(A、B)が共同してソフトを開発したとします。そして偶然にもAもBも顧客名や職員名の一覧を扱う「NameList」というクラスを作ったとしましょう。もしパッケージがなければ、AのNameListもBのNameListも名前がいっしょなので区別がつきません。そのようなときにパッケージがあれば双方の「NameList」クラスを下記のように区別して利用できます。

例:同名クラスのパッケージによる区別

 
 
組織Aの「NameList」クラス
jp.co.A.comm.NameList
組織Bの「NameList」クラス
jp.co.B.common.NameList

また、各パッケージを役割や機能ごとに作れば役割に応じて外部のクラスからアクセスできるかどうか、メソッドを呼び出せるかなどを制御することができます。

簡単にいうとパッケージとは住所のようなものです。事実どこの組織も自社のパッケージを命名する時には組織のインターネットドメイン名を利用します。例えばウインワンズウエイ株式会社の作ったクラスであれば必ず「jp.co.wownet」パッケージ以下に属しています。当然アプリケーションや、機能によって下記のようにさらに細かくパッケージ分けされます。

jp.co.wownet.「アプリケーション名」.「機能名」.「クラス名」

自分のクラスのパッケージ宣言はソースコードの一番先頭にpackage句を用いて記述します。そして自クラスと異なるパッケージに属したクラスをコードの中で利用するためには、クラスの宣言文の前にimport句を用いてどのパッケージ、クラスを利用するかを宣言する必要があります。

例:jp.co.wownet.education.Sample01クラスの宣言部分

     
 

//自分の属しているパッケージの宣言
package jp.co.wownet.education;

//Vectorクラスをインポート
import java.util.Vector;

//java.ioパッケージに属するもの全てをインポート
i
mport java.io.*;

//通常のクラス宣言(以下省略)
public class Sample01 { ・・・・・・・

 
     

実際に自分でパッケージを作り利用する場合には、もう一つ注意する点があります。Javaにおけるパッケージとはそのままディレクトリの階層と同一だと考えてください。例えばjp.co.wownet.education.Sample01クラスの場合は、下図のようにjpディレクトリの下のcoの下のwownetの下のeducationの下にあるSample01.javaがソースファイルで、同じくjpの下のcoの下のwownetの下のeducationの下にあるSample01.classがクラスファイルだと言うことです。

図:jp.co.wownet.education.Sample01クラスの配置場所の例

このときコンパイルを正常に行うためには、jpディレクトリが存在する場所(上図ならc:\javastudy\packagesampleディレクトリ)で下記のようにjavacを発行します。

javac -classpath . jp\co\wownet\education\Sample01.java

また、実行時には同じ場所で以下のようにjavaコマンドを発行します。

java -classpath . jp.co.wownet.education.Sample01

パッケージの意味と利用法は大まかに以上となります。Javaにおいて見通しの良いプログラミングを行うためには、パッケージの利用がポイントになってきますのでよく理解しておいてください。

 

・アクセス制御

アクセス制御とは、正確にはクラスやメンバーに対する他クラスからの利用制御のことです。プログラムではメンバーのアクセスを制御する必要のある状況が頻繁に起こります。例えば情報のカプセル化などを行った場合、内部の情報は隠蔽しておきたいのでクラスフィールドに対してメソッドを通さず直接アクセスされては困ります。そのような時にアクセス制御を用いて自分のクラス内部からのみ利用を許可するようにフィールドの宣言を行えばよいのです。では具体的にJavaにおけるアクセス制御とは、下記の4つが挙げられます。

  1. public
  2. protected
  3. 宣言無し
  4. private

そしてこれらのアクセス制御の対象にはクラス、コンストラクタ、フィールド、メソッドがあります。事実上クラスはpublic以外は存在しないのでフィールドやメソッドに対する制御だと考えてかまいません。またいわゆるインナークラスに関してはフィールドなどと同じ扱いになるのでpublic以外も存在しますが詳しい話は省きます。

アクセス制御に関してはやはり2つの側面があります。1つ目は「他クラスからのアクセス制御」、2つ目は「サブクラスからのアクセス制御」です。下表を見て下さい。

表:アクセス制御一覧

宣言子
他クラスからのアクセス
サブクラスからのアクセス
public
protected
同一パッケージから可
宣言無し(default)
同一パッケージから可
不可
private
不可
不可

まずはpublicとprivateから見ていきましょうpublicはいかなるクラスからのアクセスであろうと許可し、privateは自分以外のいかなるクラスからのアクセスであろうと拒否します。面倒なのはprotectedと宣言無しの場合です。protectedの場合は自分と同一のパッケージに所属するクラス自分のサブクラスからのアクセスが許可されます。一方で宣言無しの場合は自分と同一のパッケージに所属するクラスからのアクセスのみ許可され、サブクラスからのアクセスは許可されないことに注意してください。

これがアクセス制御の基本ですが、基本的には他クラスから利用するメンバーはprivate以外で自クラスでしか利用しないメンバーはprivateで宣言すると良いでしょう。またこれはコーディング全般において言えることですが、可変フィールドに対するアクセスは特殊な理由がない限りpublicにしないようにしてください。理由は下図のように仕様変更に弱いクラスとなるからです。なぜならpublicな変数に対して直にアクセスを許可してしまうと間にメソッド(setやgetなど)が介在しないために、値の取り扱い部分で仕様変更が出た際にフィールドにアクセスしている全てのクラスに変更が必要となります。一方フィールドに対してメソッドによるアクセスが提供されているとそのメソッドに変更を加えれば、メソッドを呼び出しているクラスには変更が及ばず最小限の修正で対応できます。このように、いかなる場合であろうとクラスの設計は変更の余地のある形で行うのが望ましいでしょう。

図:可変フィールドのアクセス権限

可変フィールドに対してpublicなアクセスを許可しているとあらゆるクラスが、ただの変数のように容易にフィールドの値を変更や取得することが可能になります。一方で、仕様変更によりフィールドの値にサフィックス(接尾文字)を付加したい時などにおいて外部クラスに変更を加える必要があるため非常に仕様変更に弱い構造となります。
 
可変フィールドに対するアクセスを制限しsetやgetなどのメソッドにより値の変更や取得を行うようにした場合、フィールドにアクセスしようとすると必ずメソッドを経由することになります。こちらでもSampleクラス1のように、仕様変更によりフィールドの値にサフィックス(接尾文字)を付加したいという要求が来たとします。するとこちらのクラスの場合はフィールドに対するアクセスは必ずメソッドを経由しているので、setもしくはgetのメソッド内部でフィールドの値にサフィックスを付加する機能を追加するだけです。

 

 
↑上へ 目次へ戻る