はじめに
この章では、カプセル化とアクセス修飾子について学習します。カプセル化はJava言語の3大要素(カプセル化、継承、ポリモーフィズム)の一つです。カプセル化によりオブジェクトの独立性を保つことができます。
また、mainメソッド、クラスとソースファイルの関係、クラスのインポートなどについても学習します。
これらの知識は、OCJPなどの試験でよく問われる内容です。しっかり理解するようにしましょう。
目次
- アクセス修飾子
- カプセル化
- mainメソッドの位置づけ
- Javaファイルの規則
- import文
- 章のまとめ
目標
- Javaの主な特徴であるカプセル化について理解する。
- クラスとソースファイルの関係、クラスのインポートの書き方について理解する。
アクセス修飾子
これまでのクラスや、クラスの構成要素であるメソッドに対して、先頭にpublic
というキーワードを付加している場合としていない場合がありました。これらはアクセス修飾子
というもので、付加した要素にアクセスできるかできないか
を表します。
「アクセスできる
」とは「見える(可視)
」ということです。見えていればそれらを利用することができます。アクセス修飾子
は、クラス
やメンバ変数(フィールド)
、メンバメソッド
、コンストラクタ
に付加することができます。
Javaではクラスはそれぞれ特定のパッケージの中に配置されています。パッケージ内
では、どのクラスも互いに「見える
」状態です。つまり、アクセスできる状態
が標準の状態です。これをデフォルト
といい、アクセス修飾子が何も付加されていない状態
をデフォルトアクセス
といいます。デフォルトアクセスの場合、異なるパッケージからはアクセスすることができません。異なるパッケージからアクセスしたい場合は、public修飾子
を付加します。
publicアクセス修飾子
classにpublic修飾子
を付与すると、異なるパッケージ
から「見える(可視)
」状態になり、他のクラスから利用することが可能になります。
アクセス修飾子を付与できるのは、classだけではなく、メンバ変数(フィールド)やコンストラクタ、メソッドなどに付加して、さらに細かいアクセス制御ができるようになっています。
ただし、classにpublicがついていない状態で、クラスの構成要素にpublicを付けても無駄です。
クラスそのものがパッケージを超えて見えない状態で、そのクラスの内部の構成要素が見えるはずはありません。
例題(publicアクセス修飾子(クラスにpublic修飾子が付加されていない場合))
以下は、publicがついていないクラスは、異なるパッケージのクラスからはアクセスできない例です。
以下のEmployeeクラスとEmpExecクラスを作成し、実行結果を確認してみましょう。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7A |
クラス名 | Employee |
package chapter7A; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7B |
クラス名 | EmpExec |
package chapter7B; |
コンパイル例:> javac chapter7A¥Employee.java
> javac chapter7B¥EmpExec.java
chapter7B/EmpExec.java:3: エラー: chapter7AのEmployeeはpublicではありません。パッケージ外からはアクセスできません
import chapter7A.Employee; //コンパイルエラーが発生する
^
chapter7B/EmpExec.java:17: エラー: chapter7AのEmployeeはpublicではありません。パッケージ外からはアクセスできません
Employee emp = new Employee(); //コンパイルエラーが発生する
^
chapter7B/EmpExec.java:17: エラー: chapter7AのEmployeeはpublicではありません。パッケージ外からはアクセスできません
Employee emp = new Employee(); //コンパイルエラーが発生する
^
エラー3個
上記、パッケージchapter7AのEmployeeクラスがデフォルトアクセスになっており、異なるパッケージのchapter7Bからはアクセスすることができない為、コンパイルエラーが発生します。
例題(publicアクセス修飾子(メソッドにpublic修飾子が付加されていない場合))
今度は、chapter7AのEmployeeクラスをpublicに修正し、disp()メソッドをデフォルトアクセスにして確認してみましょう。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7A |
クラス名 | Employee |
package chapter7A; |
コンパイル例:> javac chapter7A¥Employee.java
> javac chapter7B¥EmpExec.java
chapter7B/EmpExec.java:20: エラー: Employeeのdisp()はpublicではありません。パッケージ外からはアクセスできません
emp.disp();
^
エラー1個
上記、パッケージchapter7AのEmployeeクラスのdisp()メソッドはデフォルトアクセスで、他のパッケージであるchapter7Bからはアクセスできない為、コンパイルエラーが発生します。
例題(publicアクセス修飾子(クラスおよびメソッドともにpublic修飾子が付加されている場合))
今度は、パッケージchapter7AのEmployeeクラスのdisp()メソッドを、public修飾子へ修正して確認してみましょう。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7A |
クラス名 | Employee |
package chapter7A; |
コンパイル例:> javac chapter7A¥Employee.java
> javac chapter7B¥EmpExec.java
実行例:> java chapter7B.EmpExec
社員名:福山雅治
社員番号1000
privateアクセス修飾子
publicとは逆に、「見える(可視)
」範囲を同じクラスの中だけに限定
したいというときは、private
修飾子を利用します。privateを付けると同じパッケージのクラスであっても見えなくなります。ただし、privateをclassに付けることはできません。
classに付けることができるのはpublicだけです。
例題(privateアクセス修飾子1)
以下は、他クラスからprivateが付与している要素へアクセスした場合の例です。
新たにパッケージchapter7を作成し、EmployeeクラスとEmpExecクラスを作成し、実行結果を確認してみてください。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | Employee |
package chapter7; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | EmpExec |
package chapter7; |
コンパイル例:> javac chapter7A¥Employee.java
> javac chapter7B¥EmpExec.java
chapter7/EmpExec.java:20: エラー: empNameはEmployeeでprivateアクセスされます
emp.empName = "山田太郎"; //コンパイルエラーが発生
^
エラー1個
上記、Employeeクラスの構成要素であるメンバ変数empNameはprivateが付加されており、異なるクラスであるEmpExecクラスからはアクセスすることができない為、コンパイルエラーが発生します。
先ほど作成したEmployeeクラスとEmpExecクラスの以下の箇所を修正し、実行結果を確認してみてください。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | Employee |
package chapter7; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | EmpExec |
package chapter7; |
コンパイル例:> javac chapter7¥Employee.java
> javac chapter7¥EmpExec.java
実行例:> java chapter7.EmpExec
社員名:福山雅治
社員番号1000
アクセス修飾子の比較
アクセス修飾子をまとめると、以下です。
アクセス修飾子 | アクセス修飾子による制限 |
---|---|
private | 同一クラス内に定義されたメソッドやコンストラクタからだけアクセスできる |
デフォルドアクセス(修飾子なし) | 同一クラス内に定義されたメソッドやコンストラクタからアクセスできる他、他のクラスでもソースコードが同じパッケージ内にあれば、そのメソッドやコンストラクタからアクセスできる。 |
public | 条件なし。自由にアクセスできる。 |
private修飾子
を付けると自身のクラス内のメンバーだけ
がアクセスできるようになります。
またpublic修飾子
を付けると外部の異なるパッケージのクラスから
でもアクセスが可能になります。
カプセル化とデータ隠蔽
カプセル化とは
カプセル化
とは、オブジェクト内に属性(メンバ変数)
とその属性にアクセスする操作(メンバメソッド)
を、1つのメソッド
にまとめて定義する
クラスの設計技法です。
カプセル化
をおこなうことで、オブジェクトの独立性を確保
することができます。
情報隠蔽とデータ隠蔽
カプセル化を実現するために、情報隠蔽
とデータ隠蔽
という2つの設計技法があります。
情報隠蔽
とは、外部のオブジェクト
に対して、公開するメンバ
と、非公開にするメンバ
を分けることをいいます。
データ隠蔽
とは、オブジェクトの属性(メンバ変数)
を隠蔽
し、外部
のオブジェクトに対しては、特定の操作
手順のみを公開
することをいいます。
具体的には、オブジェクトの属性(メンバ変数)
をprivate修飾子
を付与し、他のオブジェクト
から直接アクセス
できないようにします。
その代わり、メンバ変数の値
を参照できたり、メンバ変数の値を設定
するための専用のメソッド
をpublic修飾子
を付与し、他のオブジェクトからメソッド
を通してメンバ変数
へアクセス
できるようにします。この専用のメソッドのことを、アクセサメソッド
といいます。
アクセサメソッド
には、値を取得
するためのメソッド(ゲッター
)と、値を設定
するためのメソッド(セッター
)があります。
カプセル化の定義方法
以下、カプセル化の定義です。
例題
先ほど作成した、EmployeeクラスとEmpExecクラスの以下の箇所を修正し、実行結果を確認してみてください。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | Employee |
package chapter7; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | EmpExec |
package chapter7; |
コンパイル例:> javac chapter7¥Employee.java
> javac chapter7¥EmpExec.java
実行例:> java chapter7.EmpExec
社員名:福山雅治
社員番号1000
empName:自身の名前
empNo:2000
上記、Employyeクラスをカプセル化
しています。そして、アクセサメソッド
を利用し、メンバ変数に値を設定や取得をおこなっています。カプセル化
することで、メンバ変数の値を直接設定することを禁止
し、代わりに、アクセサメソッド
を利用して間接的にメンバ変数へアクセス
することが可能になります。
mainメソッドの位置づけ
メソッドにstatic修飾子
が付与されるとクラスメソッド
と呼ばれます。mainメソッドはstatic修飾子
が付加されたクラスメソッド
です。
クラスメソッドはプログラム実行開始直前
にインスタンス化
され、プログラムが終了するまで、そのまま存在し続けています。
常に存在しているので、いつでも実行できる状態
にあります。これがstatic(静的)
と呼ばれる由来です。
Java言語では、最初にmain()メソッドが呼ばれる
仕組みになっています。main()メソッドが、staticが付加されたメソッド(クラスメソッド
)でなければならないのは、実行開始直前
に準備されている必要があるからです。
一方、static修飾子の付加された変数やメソッドは、new演算子
によって実行開始後
にインスタンス化
されます。
これに対して、static修飾子の付加されたmainメソッドは、クラスの中ではstaticメンバという位置付けです。
プログラムの実行開始直前に、一度だけインスタンス化され、プログラム終了まで存在し続けます。
Javaファイルの規則
1つのファイルに1つのクラスを定義するのが基本ですが、現実には状況に合わせてオプションがあります。ここでは知っておかなければならないJava言語のオプションについて学習していきましょう。
クラス名とファイル名の規則
Java言語の規約
では、ソースプログラムを書いたファイルの拡張子
は「.java
」とすると決まっています。また、クラス名
とファイル名
は、原則同じ
でなければなりません。クラス名が「Car」で定義した場合、それを保存するファイル名は「Car.java」でなければなりません。
クラスファイルの規則
エディタで書かれたプログラムはただの文字列です。エディタでJava言語で書いたプログラムはソースプログラムといいます。第1章で学習しましたとおり、動かす為にはソースプログラムをコンパイラによって、実行可能ファイル(Javaバイトコード)
に変換する必要があります。今までも以下のコマンドを実行し、コンパイルをおこなってきました。
コンパイラによって、コンパイルすると実行可能ファイル(Javaバイトコード)
である.classファイル
が生成されます。
この一連の作業のことを、一般的には「ビルド(build)
する」といいます。
javaファイルの規則
一つのクラスを一つのソースファイル(.javaファイル)に書くのが原則ですが、一つのソースファイル(.javaファイル)にいくつものクラスを書くことができます。ただし、説明や学習時のために利用されるだけであって、一般的には推奨されていません。
ソースファイル(.javaファイル)
をコンパイルすると、定義されているクラスごと
に実行可能ファイル(.classファイル)
が生成されます。
1つのファイルに複数のクラスを定義
した場合には、ファイル名は以下のような制約があります。
public修飾子
を付加したクラスがあれば、ソースファイル名はそのクラスと同じ名前
にしなければならない。public修飾子
を付加したクラスが1つもない場合
には、ソースファイル名は何をつけても良い
。
例題(複数のクラスを含むJavaファイル)
以下、一つのソースファイル(.javaファイル)に複数のクラスを定義した場合の例です。
AクラスとBクラスとCクラスを一つのファイルへ定義し、実行結果を確認してみてください。
項目 | 名前 | 備考 | |
---|---|---|---|
プロジェクト | alj_study | ALJEP研修用 | |
パッケージ | chapter7 | 第7章 | |
クラス名 | A | Aクラス | public |
クラス名 | B | Bクラス | デフォルトアクセス |
クラス名 | C | Cクラス | デフォルトアクセス |
ソースファイル名 | A.java |
package chapter7; |
コンパイル例:> javac chapter7¥A.java
A.javaのソースファイルをコンパイルすると、A.class、B.class、C.classが生成されます。
実行例:> java chapter7.A
Aクラスです。
> java chapter7.B
Bクラスです。
> java chapter7.C
Cクラスです。
今回は全てのクラスでmain()メソッドを定義している為、Javaコマンドで実行することができます。
尚、通常は1つのファイルに1つのクラスを定義することが一般的です。
特に理由がない限り、1つのファイルに1つのクラスを定義するようにしましょう。
import文
第1章で学習しましたとおり、Javaプログラミングでは、クラスはパッケージに分けて作成します。異なるパッケージの機能を利用する場合、import作業が必要です。ここではimportについて解説します。
パッケージ管理
1つのパッケージには関係のあるクラスを集めて、パッケージ全体で意味のある機能
を実現するようにします。この時、パッケージの中のクラスは、互いに違う名前でなければなりません。同じ名前のクラスは作れないルールになっています。パッケージが違えば、同じ名前のクラス名をつけることができます。
パッケージの命名規則
パッケージ名
は、名前が衝突するのを避けなければなりません(ユニークな名前でなければならない)。
その為実務では、所属する企業のインターネットドメイン名
を逆順にしたもの
を推奨
しています。
尚、Java言語のクラスの正しい名前は、パッケージ名を含めた名前
です。これを、完全修飾名
といいます。
完全修飾名での呼び出し
完全修飾名(パッケージ名.クラス名)
という形で、クラスを利用してみましょう。
今回は、java.utilパッケージにあるArraysクラスを完全修飾名
※Arraysクラスは JavaAPIで提供されているクラスです。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | ArrayExec1 |
package chapter7; |
しかしながら上記のように書くと、記述が長くなってとっても面倒です。
そこでJavaでは通常、他のパッケージのクラスを利用したい時はimport文
を使います。
import文での呼び出し
import文
の構文は以下です。
import パッケージ名.使用したいクラス名; |
先ほど、作成したArrayExec1クラス
を以下のように修正してみましょう。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | ArrayExec1 |
package chapter7; |
コンパイル例:> javac chapter7¥ArrayExec1.java
実行例:> java chapter7.ArrayExec1
[100, 200, 300]
上記の様にプログラムの先頭で一度だけ、import文
を使って完全修飾名
でクラス名を登録しておけば、プログラムの中ではクラス名だけで指定できる様になります。
(import java.util.Arrays;
がimport文です。)
import文でのアスタリスクの使用
パッケージ文でクラス名を指定する箇所をアスタリスク(*)
で指定すると、そのパッケージ内のすべてのクラスが利用できます。
構文は以下です。import パッケージ名.*;
import static文
これまで、クラスメソッド(staticのメソッド)を利用する場合には以下の様に書いていました。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | ArrayExec1 |
package chapter7; |
コンパイル例:> javac chapter7¥ArrayExec1.java
実行例:> java chapter7.ArrayExec1
[100, 200, 300]
上記の場合、Arraysクラスのメソッドを使う時は、Arraysというクラス名を必ずつけていましたが、import static文
を使うと、Arraysというクラス名を付けなくても、Arraysクラスで定義されているメソッド()が利用できます。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | ArrayExec1 |
package chapter7; |
コンパイル例:> javac chapter7¥ArrayExec1.java
実行例:> java chapter7.ArrayExec1
[100, 200, 300]
なお、import static文でメソッド名を指定する箇所をアスタリスク(*)
で指定すると、そのパッケージ内のクラスの全てのstaticメソッドが利用できます。
import static パッケージ名.クラス名.*; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter7 |
クラス名 | ArrayExec1 |
package chapter7; |
コンパイル例:> javac chapter7¥ArrayExec1.java
実行例:> java chapter7.ArrayExec1
[100, 200, 300]
まとめ
以下の要点を理解できたら次の章へ進んでください。
アクセス修飾子
- クラス、メンバ変数、コンストラクタ、メソッドには、アクセス条件を設定することができる
- アクセス条件を指定する場合には、アクセス修飾子を利用する。
デフォルドアクセス修飾子
- アクセス修飾子を付与しない場合、デフォルトアクセスが設定されている。
- デフォルトアクセスは、同じパッケージ内ではどのクラスも互いに「見える」状態である
(同じパッケージ内からアクセスできる状態である) - 異なるパッケージから利用可能にする場合は、classにpublic修飾子を付与する必要がある
public修飾子
- publicアクセス修飾子の場合、パッケージを超えても「見える」状態である
(同じパッケージ内+他のパッケージからアクセスできる状態である) - publicアクセス修飾子はクラス、メンバ変数、コンストラクタ、メソッドに付加できる
- クラスの構成要素(メンバ変数、コンストラクタ、メソッド)がpublicでも、クラス自身にpublicが付与されていないと、外部からのパッケージからは利用できないので注意が必要
private修飾子
- privateアクセス修飾子は、「見える」範囲が同じクラス内だけである
(同じクラス内の構成要素同士のみアクセスが可能) - privateアクセス修飾子は、メンバ変数、メンバメソッドに付加することができる
- クラスにprivateは付加することはできない
カプセル化
- カプセル化とは、オブジェクト内に属性(メンバ変数)とその属性にアクセスする操作(メンバメソッド)を、1つのメソッドにまとめて定義するクラスの設計技法のこと
- カプセル化を行うことで、オブジェクトの独立性を確保することができます
- 情報隠蔽とは、外部のオブジェクトに対して、公開するメンバと、非公開にするメンバを分けること
- データ隠蔽とは、オブジェクトの内部構造を隠蔽し、外部に対しては特定の操作手順のみを公開すること
- 属性(メンバ変数)へprivate修飾子を付与し、外部クラスからアクセスできないようにする
- アクセサメソッド(setterメソッド、getterメソッド)を定義する
mainメソッドの位置づけ
- static修飾子の付加されているメンバはプログラムの実行開始直前に、一度だけインスタンス化され、プログラム終了まで存在し続ける
- main()メソッドは、static修飾子が付与されているクラスメソッドである
- Java言語では、最初にmain()メソッドが呼ばれる仕組みになっている
Javaファイルの規則
- Java言語の規約では、ソースプログラムを書いたファイルの拡張子は「.java」とする
- クラス名とファイル名は、原則同じにする
- コンパイラ(javac)によって、コンパイルすると.classファイルが生成される
- 一連の作業のことを、ビルド(build)するといいます。
- ソースファイル名はpublic修飾子を付加したクラスと同じ名前にする
- public修飾子を付加したクラスが1つもない場合には、ソースファイル名は何をつけても良い
- コンパイルすると、ソースファイルに定義したクラスごとに.classファイルが生成される
import文
- パッケージには関係のあるクラスを集めて、パッケージ全体で意味のある機能を実現する
- 同じパッケージ内に、同じ名前のクラス名をつけることができない
- パッケージが異なれば、同じ名前のクラス名をつけることができる
- 実務では、所属する企業のインターネットドメイン名を逆順にしたものを推奨している
- 名前が衝突するのを避けなければならない(ユニークな名前でなければならない)
- Java言語のクラスの正しい名前はパッケージ名を含めた名前である(完全修飾名)
- 完全修飾名でメンバを呼び出す場合、「パッケージ名.クラス名 」で定義する
- 完全修飾名で指定した場合、import文は不要
- import文はpackage文の直後に書く
- import文で、パッケージ内の全てのクラスをimportする時はクラス名にアスタリスク( * )を指定する
- パッケージ名はドットで区切った名前で指定することもできる
- Eclipseの自動補完機能を利用すると自動でimport文を挿入できる
- import static文を定義すると、メンバ名のみで呼び出すことが可能
- import static文で、パッケージ内のクラスの全てをimportする時はメソッド名にアスタリスク( * )を指定する
- Eclipseの自動補完機能を利用すると自動でimport文を挿入できる