シーケンス図

ユースケース図で「何を作るか」要求仕様を整理し、
クラス図で「何で作るか」属性(データ)と振舞い(機能)を一体化した処理としてどうまとめるか、クラス構造とクラスの関係を整理しました。
次は処理と処理の関係がいつ発生し、いつ終わるか、時系列に沿ったオブジェクト同士の協調処理の順序や関連性をオブジェクト間のメッセージのやり取り(メソッドの起動)で表すシーケンス図を使って整理します。

シーケンス図とは
オブジェクト指向プログラミング以前には、ソフトウェアは目的の処理を実現するため必要なデータをどういう手順で処理するかに着目していました。そこで、繰返し行われる処理は関数やサブルーチンとしてまとめ、それらの関数にデータを渡すこと(関数の呼び出し)で処理を設計しました。
しかし、複雑なデータ構造を扱うようになると、データ自体についても特定の関数周辺で局所的に使われるデータといろいろな箇所で使われる可能性のあるデータを安全に区分けしたい、などの必要性が高まりました。そして、特定のデータ(属性)と関数(メソッド)を一体化してクラスにまとめ、クラス同士のメッセージ交換(インスタンスの生成や操作の起動)により、クラス同士が同調して目的の処理を実現する、オブジェクト指向プログラミングが提案されました。
このメッセージ交換をいつ行うかのタイミングを検討し、明確化するのがシーケンス図です。

シーケンス図の例
ユースケース図でふれた「映画チケットの予約」処理
(イメージをクリックすると拡大イメージが開きます。)

シーケンス図の構成要素
相互作用名

シーケンス図は矩形の枠の左上隅に相互作用名(シーケンス図の名前)を書き込みます。
相互作用名の前にはsd(sequence diagramの略称)を付けます。

ライフライン

シーケンス図で記述する処理に関係するアクターやオブジェクトがライフラインです。アクターはユースケース図に現れたアクターを書きます。オブジェクトはクラス名を矩形で囲い、インスタンスとして存在している期間を垂直に破線で書き示します。また、インスタンスの操作が実行されている期間を活性区間と呼び、ライフライン上の破線の上に縦長の矩形を乗せて示します。
インスタンスの消滅を明示する場合はライフラインの末端に×印を書きます。

メッセージ

同期メッセージ
同期メッセージの矢印形状
戻りメッセージ
戻りメッセージの矢印形状
非同期メッセージ
非同期メッセージの矢印形状
生成メッセージ
生成メッセージの矢印形状
破棄メッセージ
破棄メッセージの矢印形状
オブジェクト間のやり取り(インスタンスの生成や操作の起動と戻り)を矢印付きの線と、メッセージ名、戻り値、引数で表します。
なお、呼び出し先の操作が終了するまで呼び出し元は次の手順に進まない同期メッセージは黒塗りつぶしの三角形矢印に実線を書きます。呼び出した操作が終了し制御が戻されることを明示したい場合は、矢印に破線で戻りメッセージを書きます。また、この時呼び出した操作の活性区間は終わります。
相手の操作を呼び出し、その操作の完了を待たずに次の手順に進む非同期メッセージは矢印に破線で書きます。
この他、メッセージにはインスタンスの生成を指示する生成メッセージ、消滅を指示する破棄メッセージがあります。
※Javaでは消滅を指示する破棄メッセージを明示する必要はありません。

自己メッセージ

自分自身が持つ操作の起動は、自分自身にメッセージを送る自己メッセージを黒塗りつぶしの三角形矢印をコの字状に書いて示します。

設計に戻る

クラス図

クラス図は開発するソフトウェアを構成するクラス及びクラス間の関係を定義します。
クラス図は基本設計段階ではクラス構造の検討に、詳細設計段階では内部仕様の定義に利用します。
それぞれの段階に合わせクラスの表現粒度は適切に選ぶ必要があります。
特に、設計の最終段階ではコーディングに対する作成指示になるので、クラス構造だけでなくクラス名やメンバー名等についても確認する必要があります。

クラス図の書式

クラス名
クラスを表す矩形を上下3つの部分に分けた上段に記入します。
属性(フィールド)
クラスが持つ属性を矩形の中段に記入します。フィールド名の前にクラスの可視性(メンバーに対するアクセス可能範囲)を表す記号(後述)を付け、フィールド名の後に:(セミコロン)を書きフィールドの型を記入します。
メソッド
クラスの振舞い、操作を矩形の下段に記入します。メソッド名の前に可視性を表す記号、メソッド名の後に戻り値の型を記入します。

クラスの可視性

アクセス可能範囲 UMLの可視性記号 説明
public + すべてのクラスからアクセス可能
protected # 同じパッケージ内のクラス、もしくはパッケージ外のサブクラスからアクセス可能
パケージプライベート(指定なし) ~ 同じパッケージ内のクラスからのみアクセス可能
private 同一クラス内からのみアクセス可能

クラス間の関係
関連(association)

クラス間で、一方のフィールドで相手のクラスを参照する(has-a)関係
参照関係にあるクラス間を実線で結びます。
クラスの可視性はこの実線(依存関係では破線)の参照されるクラス側の端周辺にクラス名を、名前の前に可視性を付けて書いたり、実線の両端には多重度を書き、参照するインスタンスの数を明示することもあります。

多重度の表記

文字記号 説明
n 0以上でm及び*より少ない整数
.. 範囲
m 0以上でnより大きい整数
* 0以上でnより大きい任意の整数
nが単体で書かれればクラスのインスタンスがn個参照されることを表し、*が単体で書かれればクラスのインスタンスが任意個参照されることを表します。
また、nが範囲記号を伴ってn..mないしn..*などと書かれれば、クラスのインスタンスがn個からm個まで、ないしn個から任意個まで参照される可能性がある事を表します。

集約(aggregation)

関連と似た関係ですが、クラス同士が全体と部分になっている(owns a)関係
クラス間を実線で結び、全体側に白抜きのひし形を書きます。
部分側のクラスは、別のクラスからも参照される可能性があります。
ちなみにaggregationの意味は「(独立した部分を集めた)集合」です。

コンポジション(composition)

集約の中でも強い関係、全体クラスのインスタンスと部分クラスのインスタンスが同時に生まれ、同時に消滅する関係
クラス間を実線で結び、全体側に黒塗りつぶしのひし形を書きます。
部分側のクラスは、他のクラスから参照される事はありません
ちなみにcompositionの意味は「(すべてが一体になった)合成物」です。

依存(dependency)

一方のクラスが相手のクラスに何らかの影響を与える関係
影響を受ける(依存する)クラスから、影響を与えるクラスに矢印付きの破線をかきます。
影響を与えるとは、クラスが変更された場合、相手のクラスに影響が及ぶという事であり、依存の形態は、メソッド内で別のクラスのインスタンスを使ったり、メソッドの引数や戻り値に別のクラスのインスタンスを使う、などいろいろ考えられます。

実現(realization)

依存の一種ですが、Javaのインターフェースの実装に相当する関係
実装クラスからインタフェースに破線の白抜き三角形矢印を引き、ステレオタイプ<< interface >>をインターフェース名の上に記述します。

汎化(generalization)

あるクラスの性質、振る舞いを一般化して新たなクラスを定義した時の両クラスの関係
一般化して作成したクラスをスーパークラス(親クラス)、一般化するクラスをサブクラス(子クラス)と呼び、一般化の方向(サブクラスからスーパークラス)へ実線の白抜き三角形矢印を引きます。
汎化によって定義したスーパークラスをもとに考えると、スーパークラスと類似の性質や働きを持ちながら一部特殊化した新たなサブクラスを派生させることが出来き、Javaの継承に相当します。
※「一般化する」するとは、ある物から特殊な性質を取り除き、多くに共通する普遍的な性質を抽出、概念化する事です。

設計に戻る

データ型

コンピュータ用語の中には日常聞きなれない単語があります。「リテラル」もそのような用語の一つです。リテラルとはプログラムの中で具体的な値を直接書いた時の、その値を指します。

int num = 10;
char moji = ‘A’;
return true;

英語の意味は「(意味が)文字通りの」、「事実に即した」、「融通が利かない」などで、「そのものズバリで、変化しない」といったイメージでしょう。
プログラムの中でのリテラルには数値リテラル、文字リテラル、文字列リテラルがあります。

各種リテラル

種類 表記
整数 10進数 先頭が(マイナス符号を含む)1~9で始まる0~9の整数、但し一桁の場合は0も可 -8
16
2進数 先頭が0b(又は0B)で始まる0及び1を使ったビット列 -0b1000
0b10000
8進数 先頭が0(8進数を表す文字記号)で始まる0~7の数列 -010
020
16進数 先頭が0x(又は0Xの16進数を表す文字記号)で始まる0~9及びa~f(又はA~F)の16進数列 -0x10
0x20
浮動小数点数 標準表記 10進数の実数(整数部、小数点、小数部) -8.0
16.0
指数表記 Eを底とする指数表記(仮数部、e(又はE)、指数部) -8.0e+0
1.6e+1
文字 シングルクォーテーションで1文字を囲う。文字はユニコードで規定される範囲。 ‘a’
‘A’
文字列 ダブルクォーテーションで文字列を囲う。文字列内の文字はユニコードで規定される範囲。 “A”
“ABC”

リテラルに対して、変化する値を扱うのが変数です。
メモリー上の特定の領域に名前を付けて、その名前でその領域にデータを記録したり、書き換えたり、参照できる。これが変数であり革新的なアイディアでした。プログラム言語はここから始まったといっても良いでしょう。
しかし、変数だけでは解決しない事がありました。それは変数の型です。
リテラルはその物のズバリの表現なので、コンパイラーはその表現に合わせ必要な記憶領域を決まることが出来ましたが、変数は単なる名前であり、メモリー上の番地を示しているだけです。コンパイラはどのくらいの記憶領域をそれぞれの変数に対して割り当ててよいのか分かりません。そこで、変数ごとに記憶するデータに合わせた型を宣言してもらう必要がありました。

変数の宣言

書式

データ型  変数名;

同一型の変数は「,」で区切り一行に複数書くことが出来ます。
但し、変数ごとのコメントは付けられないので要注意

データ型  変数1の名前, 変数2の名前, … ;
変数の宣言はC言語などオブジェクト指向プログラミング以前のプログラム言語では、プログラムの先頭で宣言するのが決まりですが、Javaではプログラムの可読性を上げるため、変数宣言は変数を使用する直前に行う事が推奨されています。

データ型
データ型はプログラム言語により(開発思想の違いから)若干の違いがあります。
Javaでは大きく基本(プリミティブ)型、参照型の二つに分かれます。

基本型は4種類、8型に分かれています。

種類 型名 ビット幅 備考
整数 byte 8
short 16
int 32 リテラルのデフォルト
long 64
浮動小数点数 float 32
doubl 64 リテラルのデフォルト
文字 char 16 ユニコード1文字のみ
真偽値 boolean true/false(小文字のみ)

※型名は小文字のみ

(C言語と比べた)Javaの型の特徴

数値と文字は型として独立している。
文字数(記憶領域サイズ)の確定している文字は基本型、文字数の確定しない文字列は参照型。文字列の内容が1文字でも文字列は文字列で、扱いは異なる。
真偽値が基本型として存在し、数値(0や1)での真偽値表現はしない。

データ型ごとのデフォルト値

データ型 デフォルト値
整数 0
実数 0.0
文字 ‘¥u0000’
(印字は半角の空白)
真偽値 false
基本型の変数は宣言によりメモリ上に記憶領域が確保され、デフォルト値で初期化されます。
但し、デフォルト値のままではコンパイルエラーになり、明示的な代入又は初期化演算子による初期値設定が必須です。

参照型は配列や文字列、オブジェクトなど構造を持ったデータの型で、記憶領域のサイズが個々に異なるためデータの実体と実体への参照情報をセットにしてデータを記憶します。また、サイズの決まった情報とサイズが任意の情報を効率よく管理するため、この二つの情報はJVMが管理するメモリ空間の中の別々の領域に記憶されています。
Javaは基本的にプログラマにメモリ管理を意識させない言語ですが、この参照型は記憶領域の確保法が基本型と異なるので、JVMのメモリ管理について少し詳しく見てみましょう。

参照型データの記憶
JVMの管理するメモリ空間には、管理方式の異なる領域がいくつかありますが、参照型データはスタックとヒープという領域を使って記憶します。

スタック(Stack)
線形のデータ構造で、プッシュ/ポップによる簡潔な管理の為素早いアクセスができます。メソッドの実行順の制御情報、ローカル変数の基本型の値や参照型の実体参照情報を記憶します。
メソッドの再帰呼び出しなどでこの領域が一杯になると、JVMはStackOverflowErrorが発生します。

ヒープ(Heap)
アクセスは低速ですがガーベージコレクションを含めた複雑な管理が行われる非常に大きな領域です。クラスのインスタンス、参照型データの実体など動的なデータを記憶する領域でガーベージコレクションの対象になっています。なお、クラス構造やコンスタントプールなど静的なデータはピープの一部であるメソッド・エリアに記憶されます。
インスタンスや参照型データを大量に作成しヒープが一杯になると、JVMはOutOfMemoryErrorを発生します。

参照型データのメモリー上の配置

参照型データの実体はヒープ領域に確保され、ここへの参照情報がスタック領域に確保されます。

配列データの記憶
参照型データの一つである配列を使って、参照型データの情報がどのように管理されているか次のケースで見てみましょう。

1)
int型で要素が1つの配列を二つ(intArry1とintArry2)を作ります。
2)
intArry1の配列変数(配列の実体を参照する情報)をintArry2の配列変数に代入します。
3)
intArry1の実体の内容を変更し、intArry2の内容はどうなるか確認します。
プログラム

class TestArray {
	public static void main(String[] args) {
		int[] intArry1 = new int[1];
		int[] intArry2 = new int[1];
		System.out.print("intArry1[0]=" + intArry1[0] + "\nintArry2[0]=" + intArry2[0] + "\t\t... 1");			// 1)

		intArry1[0] = 1;
		intArry2 = intArry1;
		System.out.print("\nintArry1[0]=" + intArry1[0] + "\nintArry2[0]=" + intArry2[0] + "\t\t... 2");		// 2)

		intArry1[0] = 10;
		System.out.print("\nintArry1[0]=" + intArry1[0] + "\nintArry2[0]=" + intArry2[0] + "\t\t... 3");		// 3)
	}
}

実行結果

>java TestArray
intArry1[0]=0
intArry2[0]=0 … 1
intArry1[0]=1
intArry2[0]=1 … 2
intArry1[0]=10
intArry2[0]=10 … 3
>

配列の参照経路と配列要素の内容変化
上記の各ケースにおいて参照型データの情報がスタックとヒープ間でどのように管理されているのか見てみましょう。

1)
intArry1、intArry2の実体用の領域がヒープに、そこへの参照情報がスタックに格納され、各配列の実体(唯一の要素である0番目の要素)にはint型のデフォルト初期値0が入ります。
2)
intArry2の配列参照情報にintArry1の配列参照情報を代入したため、intArry1もintArry2も同じ配列を参照します。このため、intArry2の要素には値を代入していないのに、整数リテラル1を代入したintArry1の要素と同じ値になっています。
3)
また、intArry1の要素の内容を変更すると、intArry2の要素の内容も同じ値に変ります。

以上のように、配列など参照型データは実体とその参照情報の組み合わせで管理されるため、その扱いには注意が要ります。
なお、参照型でもString型はプログラムの中で頻繁に使われる文字列としての扱いが更に加わるので、他の参照型データとは異なる独自の挙動を持っています。

プログラミングに戻る

インスタンス

クラスは設計図、設計図を元に実体を作って使います。そこで、クラスを元に実体を作る作業をインスタンス化と呼び、出来上がった実体がインスタンスです。」と多くの教材は説明します。

ではなぜ、そうしなければいけないのでしょう
そうすると何が有難いのでしょう。

設計図を元に物を作ると、出来上がるのは全て同じものです。
設計図は寸分違わない物を作るための指示書です。
この様なプログラムの再利用も必要でしょう。関数やサブルーチンなどは何度呼んでも同じ動きをします。ですから、設計図のようなプログラムの再利用はオブジェクト指向プログラミング以前のプログラミング言語でも可能でした

ソフトウェアの利用現場を考えてみましょう。
以前のプログラム言語ではできなかったプログラムの再利用とは、元のプログラムを利用して少しずつ違ったプログラムを瞬時に作ることです。関数やサブルーチンなど以前からの仕組みで出来なかったことは、まさにこの事です。「クラスは設計図」という説明では説明が付きません。

このコースではclassは同じ種類の集合を分類したものと説明しました。つまり、概念、コンセプトです。概念から物を作ると、作るたびに概念の解釈が少しづつ変わり、似てはいても違う物が出来るはずです。
つまり、classを元に実体を作るときも、似てはいても少し違う実体を作りたいのです。この仕組みがインスタンス化です。

例えば、クラスの説明ページで示した、チケット販売システムを思い出してください。
A席チケット販売システムも、B 席チケット販売システム、S席チケット販売システムだって基本的にはほとんど変わりません。チケットの価格と販売される席の数が違うだけでしょう。つまり、属性は多少違っても、振舞いはほぼ同じです。

これを関数で作ろうとすれば、ほとんど同じ関数を三つ作ることになり、何かを修正しようとすれば三つの関数それぞれに同じ修正を加えなければいけません。これがclassとinstanceならばclassを直すだけで全てのinstanceが同じように変わります。ましてclassを再コンパイルするだけで再リンクは不要ですから、ソフトウェアを使用しながら機能の変更が可能です。(テストは事前に十分行わなければいけませんが)

以上が、面倒な手間に見えるインスタンス化の有難さです。

次は、このインスタンス化を行うためのコンストラクタです。

書式

修飾子 コンストラクタ名 (引数リスト ) {
   処理
}

三つの条件

コンストラクタ名はクラス名と同一
戻り値型は記述しない
newと一緒にしか使えない(インスタンス生成時以外は呼び出しができない)

※クラス名がメソッド名と同じでも戻り値型を記述している場合は、通常のメソッドとして解釈されます。
※インスタンス生成時の記述で引数リストが対応していないと、コンパイルエラーが発生します。

独自にコンストラクタを定義すると、デフォルトコンストラクタは作られません。にも拘わらす、引数なしのコンストラクタ(デフォルトコンストラクタと同一)を呼ぶとコンパイルエラーになります。

多少違ったインスタンスを作るために、コンストラクタのオーバーロードを使います。また、共通部分の記述を簡略化するためオーバーロードしたコンストラクタから、ほかのコンストラクタを呼び出すためにthis(引数リスト);が使えます。なお、スーパークラスのコンストラクタを呼び出す場合にはsuper(引数リスト);を使います。

クラスが継承関係にある場合、スーパークラス分のインスタンスから生成しなければいけません。そこで、サブクラスのコンストラクタの先頭でスーパークラスのコンストラクタを呼出す必要があります。もし、プログラマーが明示的にスーパークラスのコンストラクタを呼出さないと、コンパイラは引数なしのスーパークラスのコンストラクタを呼出すコードを自動的に追加します。もし、スーパークラスに(独自のコンストラクタを記述したため)引数なしのコンストラクタが存在しないとコンパイルエラーが発生します。
※何かの処理の後でスーパークラスのコンストラクタを呼出すとコンパイルエラーになります。

また、サブクラスでコンストラクタがオーバーロードされていて、明示的にスーパークラスのコンストラクタを呼び出した後にthis();を使ってオーバーロードした別のコンストラクタを呼出すと、別のコンストラクタ側でもスーパークラスのコンストラクタを呼ぶので、スーパークラスのコンストラクタが2回呼出されることになります。このような事態を避けるため、スーパークラスのコンストラクタを呼び出した後にthis();を記述するとコンパイルエラーが発生します。
※スーパークラスのコンストラクタをインスタンス化の間に二回以上呼ぶとコンパイルエラーになります。

アクセス修飾子
コンストラクタには全てのアクセス修飾子が指定できます

public
どのクラスからでも対象のクラスをインスタンス化できる。
protected
継承関係にあるサブクラスや同一パッケージ内のクラスだけが対象のクラスをインスタンス化できる。
package default
同一パッケージ内のクラスだけが対象のクラスをインスタンス化できる。
private
非公開のコンストラクタを定義します。
非公開のコンストラクタの用途は、あるアプリケーション内でインスタンスが1つしかないことを保証したり、コンストラクタをオーバーロードして複数定義し、公開するコンストラクタと非公開にするコンストラクタに分ける(公開コンストラクタの中で非公開コンストラクタを呼ぶ)ためにも使います。

クラスに戻る

クラス及びインスタンスの初期化

似ているけれども、同一ではない個々のインスタンスを作りだすのが初期化処理です。
初期化はコンストラクタで行うのが一般的ですが、初期化はそれだけではありません

段階的に行われる初期化

1.
クラスロード時にスタティックイニシャライザが実行され、クラス変数(static変数)の初期化が行われる。
2.
クラスのフィールドで宣言した変数を既定値で初期化(初期値を代入)する。
3.
オブジェクトの生成時にインスタンスイニシャライザが実行される。
4.
次にコンストラクタが実行され、引数などによる初期化処理が行われる。

スタティックイニシャライザ
クラスのロード時、クラス変数を初期化するために使用します。
クラス変数はインスタンス化しなくても存在し、使える変数ですから初期化が必要です。通常は初期値の代入で行われますが大量の要素を初期化しなければいけないような場合には有効です。
スタティックイニシャライザはクラスのどこにでも、いくつでも記述できますが、ロード時に実行されるのでクラスの先頭から順方向で参照が行われることに注意して、適切な位置に記述する必要があります。

書式

static{
  初期化処理
}

参考例

public class StaticInitializeSample {
	public static void main(String[] args) {

		System.out.print("static arrayの値は[");
		for(int num: StaticInitialize.array) {
			System.out.print( num );
		}
		System.out.println( "]です。");
	}
}

class StaticInitialize {
	static int[] array = new int[10];
	
	//スタティックイニシャライザ
	static{
		for (int i=0; i<array.length; i++) {
			array[i] = i;
		}
	}
}

実行結果

>java StaticInitializeSample
static arrayの値は[0123456789]です。

>

なお、JVMがスタティックイニシャライザを処理中に何らかのトラブルが発生(例えばNullPointerException)した場合、そのことを通知するクラスが存在しないため、JVMはExceptionlnlnitializerErrorを発生させ、プログラムを強制終了させます。

インスタンスイニシャライザ(初期化ブロック)
インスタンス生成時にインスタンス変数(インスタンスごとに作成される変数)を初期化します。インスタンス変数は、通常コンストラクタで初期化しますが、オバーロードした複数のコンストラクタで共通する処理がある時にはインスタンスイニシャライザで一括して初期化すればプログラムの可読性が向上します。
なお、インスタンスイニシャライザはコンストラクタより先に実行されます。

書式

{ }に囲まれたブロックで、クラスブロック直下にフィールドやメソッド、コンストラクタと
同列の扱いで記述します。

参考例

public class InstanceInitializeSample {
	public static void main(String[] args) {

		StaticInitialize si1 = new StaticInitialize();
		StaticInitialize si2 = new StaticInitialize("引数一つの");

		System.out.println("インスタンスsi1は" + si1.constracterType + si1.postFix);
		System.out.println("インスタンスsi2は" + si2.constracterType + si2.postFix);
	}
}

class StaticInitialize {
	String postFix;
	String constracterType;
	
	//インスタンスイニシャライザ
	{
		postFix = "コンストラクタを使いました。";
	}
		
	StaticInitialize() {
		this.constracterType = "デフォルト";
	}

	StaticInitialize(String type) {
		this.constracterType = type;
	}
}

実行結果

>java InstanceInitializeSample
インスタンスsi1はデフォルトコンストラクタを使いました。
インスタンスsi2は引数一つのコンストラクタを使いました。

>

クラスに戻る

フィールド

フィールドはクラスの属性を定義します。
属性自体は変数の集まりです。

どの様なプログラムも結局のところデータと処理を記述したものです。
自由気ままにデータを処理していては、良いプログラにはなりません。そこで、「構造化プログラミング」で処理についたは、こうするべきだという手本が示されました。しかし、データについては型は規定しても、使われ方が多岐にわたるのでオブジェクト指向プログラミング以前の言語では規定はなく、プログラマ任せでした。

フィールドの書式はいくつかの変数宣言(同時に初期値を設定しても良い)をクラスの先頭で記述します。何もオブジェクト指向プログラミング以前の言語における変数宣言と変わりません

Javaのデータに対する規定はどこにあるのでしょうか。それは、
フィールドのスコープ(有効範囲)と変数へのアクセス手法が明確
フィールド内の変数に対し、static修飾子を付けたスタティック変数と、修飾子を付けないインスタンス変数の使い分けが可能
ことです。これにより、使われ方が多岐にわたるデータを変数という形で扱うことが出来るようになっています。

フィールドのスコープ
勿論、フィールドが属すクラス内です。
クラス内のメソッドのローカル変数の名前とフィールド内の変数の名前が重複した場合には、ローカル変数が優先されます。そこで、フィールド内の変数をメソッド内でアクセスしたい場合は、その変数名の前にthis.を書き加えます。thisはJVMが用意してくれる変数(プログラマが宣言する必要がない)の1つで、インスタンス自身への参照が入っています。このため、「this. 変数名」と記述することで、ローカル変数ではなく、フィールド内の変数を明示する事になります。
また、メソッドが仮引数としてフィールド内の変数と同じ名前を持つ場合も同じです。仮引数名の前には何もつけず変数名だけを記述します。
なおスコープの違いから、スーパークラスとサブクラスのフィールド内に同じ名前の変数があっても名前の衝突は起きません。しかし、サブクラスからスーパークラスのフィールドにアクセスするときに名前の混乱が起きないようサブクラス内のフィールドへのアクセスにはthis.を付け、スーパークラス内のフィールドへのアクセスにはsuper.を付ければ、スコープを越えたアクセスも可能です。

static なフィールドヘのアクセス
Java では、プログラムの実行中に必要なクラスを読み込んで(ダイナミックリンクして)実行します。
クラスを読込むと、staticで修飾されたフィールド(内の変数)やメソッドは、「static領域」に配置されます。それ以外の部分は、「ヒープ領域」に配置されます。インスタンスが生成されるときには、ヒーフ領域にあるクラス定義に従ってインスタンスが生成されます。
このため、staticなフィールドはそのフィールドを持つクラスのインスタンスを作らなくても、既に存在していて使うことが出来ます。また、static なフィールドはインスタンス内には存在しないので、いくつか作られたインスタンスからstaticフィールドをアクセスすると、全てstatic領域内の同じフィールドをアクセスすることになります。
なお、static なフィールドにアクセスするには「クラス名.フィールド名」と記述するか、インスタンスを生成し「インスタンス変数名.フィールド名」(コンパイル時に「クラス名.フィールド名」に置き換えられる)でアクセスします。

クラスに戻る

時代背景

コンピュータの誕生については諸説あります
というのは機械式および電気式の計算機械は19世紀からありましたし、1940年代には暗号解読や弾道計算専用の電子機械式の計算機がいくつか作られていました。
フォン・ノイマンが提唱したプログラム内蔵方式(当初のENIACには実装されていない)と逐次処理方式をコンピュータの要件とするなら、やはり1946年に米国で開発されたENIACが最初の汎用コンピュータでしょう。ENIACは当初陸軍の資金で弾道計算用に開発されましたが、水爆開発でも使われたといわれています。

ENIACは当時の電気機械式計算機に比べ約1000倍の計算能力があったといわれていますが、プログラミングは大変だったようです。
ENIACはループや分岐、サブルーチンなどが可能で紙上でプログラムが完成しても、プログラムをENIACに設定するため、搭載されている乗算器や除算器の組み合わせをスイッチやケーブルの配線を数日かけて変更しなければいけませんでした。
数学の専門家が何日もかかったプログラミングも、1948年プログラム内蔵方式が実装された改良版ENIACによって数時間に短縮されます。しかし、ENIACの設計は特殊でその後他のコンピュータでは採用されませんでした。

1950年代に入ると軍用目的でない、商用コンピューターがUNIVAC(51年)、IBM(52年)から発表されます。
当時、プログラム言語はCPUが直接実行できる二進数を並べた機械語か、機械語をニーモニックと呼ぶ英単語の省略文字で表し命令語とするアセンブラ言語しかありませんでした。しかし、商用コンピュータの拡販のためにもより一般的な数式表現や英語表現で開発できるプログラム言語の必要性が高まり、

1954年
Fortran
科学技術計算向けプログラム言語
1959年
COBOL
事務処理向けプログラム言語

が発表され、人間が理解しやすい表現でプログラムが記述できるようになり、プログラム開発を専門に行う技術者によりプログラムが量産されるようになり、銀行や商社、大手製造企業への本格的な普及が始まりました。
また、1950年代半ばにはコンピュータの素子が真空管からトランジスタに変わり、トランジスタの小型、省電力、小発熱性からコンピュータ自体の小型化・低価格化が進みます。

1960年代に入るとハードウェアの技術革新は周辺装置にもおよび、磁気ディスク装置や高速データー転送バスなどによりコンピュータの利用分野はますます広がり、1964年にはDECが16,000ドルでミニコンピュータを販売、それまで利用が大企業に限られていたコンピュータの一般企業への普及が始まります。それに合わせてソフトウェアに対する需要は増大、1960年代後半には深刻なソフトウェアエンジニア不足が予測され「ソフトウェア危機」が叫ばれました

この状況の中

ソフトウェアの生産性を向上するためソフトウェア開発プロセスを工学的に改革する研究
移植性の高いプログラム言語の開発研究

が始まりました。

プログラムはどうあるべきかという研究の結果、1969年エドガー・ダイクストラが「構造化プログラミング」を提唱。正しいプログラムを作るためには、プログラムは上手く構造化されなければならないとして、構造化の条件を提示しました。
移植性の高いプログラム言語に対する需要は、ハードウェア技術の革新により多くのメーカーがコンピュータを提供するようになったため、研究所などでは異なるOS、異なるCPUアーキテクチャー間でのソフトウェアの共用のため、ソースプログラム互換のコンパイラーを前提としたC言語が、1972年At&Tベル研究所で開発されました。

1970年代にはマイクロコンピュータ、1980年代にはパーソナルコンピュータといわゆるダウンサイジングが加速します。プログラム言語の世界でも、ソフトウェアの大量生産、大規模開発に対応するためさらなる生産性の向上が望まれ、構造化プログラミングでは整理されなかった「データ」の扱いについても研究が行われました。
そして、データの型に基づいたいくつもの実体(インスタンス)を上手く管理する仕組みとしてクラスとその継承といった考慮からオブジェクト指向概念が生まれ、その概念を実装したプログラム言語が次々に発表されました。

Javaもこれらオブジェクト指向プログラミング言語のひとつとしてサン・マイクロシステムズにより開発されましたが、その開発経緯は他のプログラム言語とは多少異なっています。そもそも、サン・マイクロシステムズは2010年にオラクルにより吸収合併されるまでPCの上位に位置づけられていたワークステーションメーカーでした。サンの名前自体Stanford University Networkの頭文字であり、スタンフォード大学の校内ネットワーク用のワークステーション開発から1982年に創業し、1985年にはRISCチップまで自社開発していました。

そのサンが1990年代に入ると今後の有力市場は家電製品だと考え、その処理系を開発できるプログラム言語の開発に着手し、1995年にJavaの名前で発表しました。
家電製品向けの新しいプログラム言語を考えると、情報処理の専門家だけでなく一般技術者でも安全で保守性の高いプログラムが開発出来なければいけません。そこで

プラットフォーム非依存で、ハードウェアの変更に即対応できる高い移植性
コンパイラ及び実行環境による安定的プログラム稼働の検証(厳密な言語仕様とコンパイラ、JVMによる実行前検証)
プログラム実行中に生じた異常の適切な処理機構の装備(例外処理)
プログラマのメモリ管理負担の軽減(ガーベージコレクタの採用)
メモリ破壊を起こさない言語仕様(ポインターによるメモリアクセスの禁止)

など、生産性向上のためのオブジェクト指向プログラミングだけでない工夫がJavaには盛り込まれました

当初の家電製品市場への進出は時期尚早だったのか成功しませんでしたが、紆余曲折の末1990年台後半に始まるインターネットの急成長に乗り、サーバーサイドのアプリケーション開発で利用さえるようになり、近年では組み込みシステムや携帯機器、企業の基幹情報システムを担う大規模なデータベース、サーバ、スーパーコンピュータアプリケーションまで、多くの分野で使用されています。

Java言語に戻る

ユースケース図

ユースケース、分かりそうで分かりにくい言葉です。useもcaseも聞いた事があるため、勝手な解釈で分かった気になりがちですが、そうすると間違った先入観で勉強することになるのでプログラミング上の意味をなかなかとらえることが出来ません。
プログラミングではこういう用語によく出会います。そういう時は英語の意味を確認し、用語の正しいイメージを持って勉強すると効果的です。

ユースケースは一般的には「使用事例」、製品説明などで使われる場合は「適用領域」などの意味です。つまり、ユースケース図は作ろうとしているシステムがどのように利用できるのか、システムが提供するサービスや機能はどのような領域に適用できるるのかを検討し、明示するために利用します。
ユースケース図はシステム開発の工程の中では要件定義の段階で、システムが満たすべき要件を表現し、関係者間の合意形成に使われます

ユースケース
ユースケース図を描く前に、ユースケース自体は何かをもう少し考えてみましょう。
例えば、一般的なイベントのチケット販売システムを考えてみましょう。
まず、チケット販売システムはチケットを購入しようとしている顧客、公演主催者が利用するでしょう。そして劇場側も劇場の運営などのために、何らかのシステム(劇場運営システム)を通してチケット販売システムからの情報を入手するでしょう。
そして、チケット販売システムは

チケットの予約をする
チケットの予約を変更する
チケットの予約を取り消す
チケットの予約状況を確認する
チケットの予約状況を取得する

などの機能、振舞いを持つことが期待されるでしょう。

これら、対象システムは何か、システムを使う人又は物は何か、システムが提供する機能は何かを文章で書こうとすると百人百様になってしまい、関係者が内容を理解するにも時間がかかります。
そこで、これらの事を図式化の決まりに従って簡潔にまとめたのがユースケース図です。ユースケース図を使えば、一目で「システムの利用者(アクター)」が何で、「システムで出来る事(枠の内側)」、「システムで出来ない事(枠の外)」がはっきり分かり、合意形成の議論もしやすいでしょう。

ユースケース図の構成要素

対象
ユースケース図で表現したいシステムを四角形で表し、対象の名前を上部に記述します。
アクター
システムの外でシステムと相互作用するユーザーや外部システムを丸と棒で描いた人型で表します。
ユースケース
システムが外部に対して提供するひとまとまりの機能を簡潔な一文で書き、楕円で囲みます。
関係
アクターと相互作用するユースケース、及び関係のあるユースケース相互を実線で結びます。
以上の構成要素をまとめると、ユースケース図は完成します。

ユースケース図作成上の注意

ユースケースはアクターから見た機能が重要なので、外からは見えない内部的な機能、実装技術、性能は記述しません
ユースケースの表現は簡潔な一文が望ましいので、(顧客が)「チケットを予約する」のように、明確な目的語と動詞で表現します
ユースケースの抽出粒度が個々に異なると全体が簡潔にまとまらなくなるので、アクターがある一つの目的を達成するために中断せずに行う機能を単位とすると良いでしょう。必要があれば、目的の粒度に応じてユースケース図を全体と詳細に分けるのも必要です。
ユースケース図で表現できるのは、どのような機能が、どのようなアクターと関連するかであって、期待する操作手順や前提条件などは表現できませんし、表現すべきではありません。それらが必要な場合はユースケース図ではなく補助資料としてユースケース記述書(UMLでの書式規定はありません。)などを用意して記述します。

ユースケースの相互関係
同じ粒度で列記したユースケース同士に共通する部分があったり、一部を独立させた方が全体のユースケースが簡潔になる場合、ユースケース間には次の関係があるといい、それらを以下のように記述します。

extend(拡張)
あるユースケースの機能を別のユースケースが拡張する関係。
機能を拡張するユースケースから基になるユースケースに向かって点線の矢印を引き、ステレオタイプ<< extend >>と線上に記述。実線で結びます。

include(包含)
あるユースケースが別のユースケースを内部に含む関係。
包含するユースケースから包含されるユースケースに向かって点線の矢印を引き、ステレオタイプ<< include >>と線上に記述。

設計に戻る

Java言語の特徴

Java言語はプログラミング言語の変遷の中では比較的新しい言語に属します。このため、それ以前開発されたプログラミング言語の利点や課題を踏まえています。
主にSmalltalkとC言語(C++を含む)をルーツとし、多少の違いはあるものの構文はANSI-C、オブジェクト指向プログラミングはCから発展したC++及びSmalltalkの影響が大きいでしょう。

Java言語の特徴

– オブジェクト指向
オブジェクト指向の特徴はいくつかあります。オブジェクト指向を取り入れたプログラミング言語もいくつかあります。つまり、オブジェクト指向プログラミング言語といってもみな同じではありません。オブジェクト指向のとらえ方で言語が持つ特徴は変わります。
そのような中で、Javaは理想を追求したSmalltalkと実用性を重視したC++の影響を受け、両者の特徴をバランス統合してオブジェクト指向開発に必要な要素をすべてそろえている言語だといえるでしょう。
– 可搬性
プログラムはプラットフォームに依存しないバイトコードとしてコンパイルされ、JVM(Java仮想マシン)により実行されます。従って、Javaプログラムはコンパイルされた後でさえ、JVMを搭載したプラットフォームであれば、再コンパイルすることなく実行できます。この移植不要という特徴(可搬性)はプラットフォームを特定できないWeb環境で他言語にない特徴になっています。
– 例外処理
プログラムが実現する処理と処理の過程で発生する可能性のある外乱に対する処理を構造化して分離し、プログラムの可読性と頑健性を高める仕組み。
– ダイナミックリンク
実行に必要なバイトコードを実行時に探しだし動的に結合しプログラムを実行します。これによりプログラマは、プログラムの一部を改変したときでもプログラム全体を再コンパイルする必要がありません。
– 型チェック
静的な型を持つため、コンパイル時に可能な限りのエラーチェックを行います。更に、コンパイル時に最適化も行います。
– メモリ管理
メモリ管理をユーザに任せずJVMがガベージコレクションを行うので、実行中に使用されなくなったメモリは自動的に解放されるため、メモリリークなどのバグが発生しません。また、ポインタ操作が公開されていないためメモリ破壊などのバグ発生が軽減されています。
– マルチスレッド
マルチスレッド対応の言語であり、複数の処理を同時に行なう必要があるネットワークアプリケーションやGUIアプリケーションの記述に向いています。

なお、Java言語の大きな特徴であるオブジェクト指向はコンピュータの大幅な性能向上、コンピュータの利用分野の拡大に合わせ1960年台後半に危惧された「ソフトウェア危機」に対応するための研究から生まれた、大きなプログラムをブラックボック化した小さな複数のプログラム(オブジェクト)によって構成するプログラミング概念であり、仕組みです。

オブジェクト指向プログラミングの特徴

– カプセル化
データと振舞いを隠蔽する仕組み。
– 継承
既存クラスの機能、構造を共有する新たなクラスを生成することができ仕組み。
– ポリモーフィズム
プログラミング言語の各要素(定数、変数、オブジェクトなど)を異なる型に置き換えて扱う事を許す概念。

Java言語に戻る