連載

Javaオブジェクトモデリング

第3回
静的モデル:
クラスにおけるUMLとJavaのマッピング(1)


3.Javaの“クラス”

■■
3.1 クラス■■

 Javaのクラスは前回ご紹介したとおり、図13のような形になります。この構造をモデル化したJavaクラスのメタモデルは図14となります。

図13 Javaのクラス

図14 Javaのクラス メタモデル(クリックすると拡大します)
  • 1つのパッケージに属していることがある
  • 1つの親クラスをextendsしていることがある
  • 0個以上複数個のインターフェイスをimplementsしている
  • 1つの可視性を持っている
  • abstractが指定されていることがある
  • finalが指定されていることがある
  • 1つのクラス名を持っている
  • 0個以上複数個のメソッドを持っている
  • 0個以上複数個のクラスメソッドを持っている
  • 0個以上複数個のコンストラクタを持っている
  • 0個以上複数個の定数を持っている
  • 0個以上複数個のインスタンス変数を持っている
  • 0個以上複数個のクラス変数を持っている
■■3.2 クラスの種類■■

 Javaでは以下のクラスを言語仕様上特別扱いしています。
  • 配列
  • java.lang.Object
  • java.lang.Class
  • java.lang.Throwable
  • java.lang.Error
  • java.lang.Exception
  • java.lang.RuntimeException
  • java.lang.String
  • java.lang.Thread
  Javaでは、配列は特殊なオブジェクトとして実現されており、言語仕様で特別な意識をすることでC言語の配列のような効果を出しています。つまりUMLでは属性やアソシエーションの多重度という形でモデル化されるものが、Javaではクラスとして扱われているわけです。この点には注意が必要で す。
  • java.lang.Objectは、すべてのJavaオブジェクトのルートオブジェクトです。extendsによって親クラスを指定しない場合、暗黙的にこのオブジェクトが継承されることになります。

  • java.lang.Classは、クラスを表現するためのクラスであり、いわゆるメタクラスと呼ばれるものです

  • java.lang.Throwableは、Java言語においてエラーや例外を表すクラスです。メソッド定義でthrows句に記述できるのは、このThrowableのサブク ラスのみとなっています。Javaの実行系(Java VM)およびJavaプログラムはThrowableまたはThrowableのサブクラスをthrowすることで、通常のプ ログラム制御シーケンスとは異なる、異常処理用の制御シーケンスを引き起こすことができます

  • java.lang.Errorは、java.lang.Throwableのサブクラスであり、Java言語においてエラーを示すクラスです

  • java.lang.Exceptionはjava.lang.Throwableのサブクラスであり、Java言語において例外を示すクラスです。Exceptionのサブクラス(かつRuntimeExceptionのサブクラスでない)は、いわゆる検査例外と呼ばれており、throwするためにはメソッドのthrows句で指定する必要があります

  • java.lang.RuntimeExceptionはExceptionのサブクラスであり、throws句に指定する必要のない、いわゆる検査なしの例外を表すクラスです

  • java.lang.Stringは、Java言語で文字列を実現するクラスです。java.lang.Stringは、言語仕様上特別な意識がされており、あたかもプリミティブ型のような使い勝手となっています

  • java.lang.Threadは、Java言語でスレッド機能を実現するクラスです
■■3.3 インターフェイス■■

 Javaのインターフェイスは前回ご紹介したとおり、図1516のような形になります。

図15 Javaのインターフェイス

図16 Javaのインターフェイス メタモデル
  • 1つのパッケージに属していることがある
  • 0個以上複数個のインターフェイスをextendsしている
  • 1つの可視性を持っている
  • strictfpが指定されていることがある
  • 1つのインターフェイス名を持っている
  • 0個以上複数個のメソッドを持っている
  • 0個以上複数個の定数を持っている
 Javaのインターフェイスは、“定数を宣言できる”という重要な機能を持っており、UMLのインターフェイスとはこの点に大きな相違点があります。

  UMLのインターフェイスは「オペレーションの集まり」を表すものですから、定数の宣言を行うことができるJavaのインターフェイスは厳密な意味では違うものと考えることもできます。また、そもそもUMLには定数という概念はないので、「定数は属性の一種である」という仮説を持ち込まなければ、純粋にJava独自の言語機能と考えることもでき、「UMLのインターフェイス=Javaのインターフェイス」という定義は意味論上も矛盾しないと考えることもできます。いずれにしても、実用上はこのような細かな違いを厳密に扱うよりも、「Javaのインターフェイス=UMLのインターフェイス」と扱うことの方がはるかにメリットが多いことはいうまでもありませんし、本連載でもそのように扱っていきます。

■■3.4 インターフェイスの種類■■

 Javaでは以下のインターフェイスを言語仕様上特別扱いしています。
  • java.lang.Cloneable
  • java.lang.Runnable
  • java.io.Serializable
  • java.io.Externalizable
  • java.lang.Cloneableは、クローン可能なオブジェクトであることを示すインターフェイスです。java.lang.Cloneableをimplementsしたオブジェクトは、cloneメソッドでオブジェクトの複製ができるようになります。

  • java.lang.Runnableは、スレッドを割り当てることができるオブジェクトであることを示すインターフェイスです。java.lang.Runnableをimplementsした オブジェクトは、java.lang.Threadのコンストラクタに指定することで、新たに生成されたスレッド上で動作します。

  • java.io.Serializableは、直列化可能なオブジェクトであることを示すインターフェイスです。java.io.Serializableをimplementsしたオブジェクトは、java.io.ObjectOutputStreamおよびjava.io.ObjectInputStreamを用いて直列化を行うことができるようになります。

  • java.io.Externalizableは、java.io.Serializableのサブインターフェイスであり、直列化可能なオブジェクトであることを示します。java.io.Serializableとの相違点は、直列化の制御をどの程度行うことができるかという点にあります。java.io.Serializableは、直列化の制御は Java実行系が完全に行ってくれて、必要に応じて制御の一部をユーザーオブジェクト側で行えるようになっています。それに対して java.io.Externalizableは、直列化の制御のコードを必ずユーザーオブジェクト側で用意しなければなりませんが、直列化の制御を完全にユーザーオブジェクト側で行うことができるようになっています。

■■3.5 メソッド■■

 Javaメソッドのメタモデルは図17となります。

図17 Javaのメソッド メタモデル(クリックすると拡大します)
  • 可視性を1つ持っている
  • staticの指定が行われていることがある
  • finalの指定が行われていることがある
  • abstractの指定が行われていることがある
  • nativeの指定が行われていることがある
  • synchronizedの指定が行われていることがある
  • strictfpの指定が行われていることがある
  • 復帰型を1つ持っている
  • メソッド名を1つ持っている
  • 0個以上複数個のパラメタを持っている
  • 0個以上複数個の例外を持っている
 Javaメソッドはプログラミング言語上は図18のように記述されます。

図18 Javaのメソッドの文法

 可視性は、public、protected、privateおよび表記の省略の4つの指定方法が用意されています。publicが公開、protectedが子孫クラスに公開、privateが公開しない、省略がパッケージ内に公開となっています。

  メソッドの性質を示す修飾子としてstatic、final、abstractが用意されています。staticが指定されるとクラススコープのメソッドとなります。finalは子孫クラスによるメソッドのオーバーライドを許さないという指定、abstractは抽象メソッドの指定です。

  メソッドの実装を示す修飾子としてnative、synchronized、strictfpが用意されています。

  図17に示すとおり、staticとabstractの修飾子の指定によって、Javaでは3種類のメソッドを定義することができます。まず、1番上にあるのが通常のメソッドです。2番目にあるのが抽象メソッドです。抽象メソッドはメソッドのシグネチャの定義のみを行い実装は定義しません。3番目にあるのがクラスメソッドです。また、通常のメソッドは修飾子finalによって、子孫クラスでオーバーライドできないように指定することができます。

  復帰値は必ず指定する必要があります。復帰値として値を返す必要がない場合はvoidを指定します。Javaでは、メソッドのシグネチャにメソッドが送出する可能性のある例外を定義することができます。

■■3.6 コンストラクタ■■

 コンストラクタのメタモデルは図19となります。

図19 Javaのコンストラクタ メタモデル
  • 可視性を1つ持っている
  • メソッド名を1つ持っている
  • 0個以上複数個のパラメタを持っている
  • 0個以上複数個の例外を持っている
 コンストラクタにはstatic、final、abstract、native、synchronized、strictfpといった修飾子を付けることはないので、メソッドと比べるとかなり簡略された形になっています。また、コンストラクタはメソッドのような復帰型は持っていません。

■■3.7 属性■■

 JavaではUMLの属性に相当する機能として変数が用意されています。しかし、変数には多くの種類があり、その一部がUMLの属性に対応する形になっています。

3.7.1 用途による分類

 Javaの変数は用途によって図20の(1)に示す以下の種類に分類することができます。
  • インスタンス変数
  • クラス変数
  • ローカル変数
  • コンストラクタパラメタ
  • メソッドパラメタ
  • 例外ハンドリングパラメタ
 この中で、インスタンス変数とクラス変数がUMLの属性に相当します。またコンストラクタパラメタとメソッドパラメタがUMLのオペレータのパラメタに相当します。ローカル変数と例外ハンドリングパラメタは、いずれもメソッドの実装に使用するものであり、UMLのモデル要素との直接の関係はありません。

図20 Java変数の種類

3.7.2 格納方法による分類

 Javaの変数は格納する情報によって図20の(2)に示す種類に分類することができます。
  • プリミティブ型
  • 参照型
  • 配列に対する参照型
 Javaの変数には大きく分けてプリミティブ型と参照型があります。プリミティブ型の変数はプリミティブ型のデータを値として保持する変数です。それに対して参照型の変数はオブジェクトによる参照を保持する変数です。

  Javaにおける配列は、配列オブジェクトによって実現されています。このため実行モデル上は配列オブジェクトに対する参照型の変数として実現されています。ただし、文法上はC言語の配列のように利用できるように考慮されているため、配列は通常の参照型の変数とは分けて考えます。

  例えばJavaの変数のモデルは図21に示すようになります。この図ではオブジェクト内に3つの変数が定義されています。 変数balanceはプリミティブ型の変数、変数personは一般的なオブジェクトに対する参照型の変数、変数personsは、配列オブジェクトに対する参照型の変数となっています。

図21 Java変数のモデル

3.7.3 属性に相当する変数

 UMLの属性に相当するJavaの変数はインスタンス変数とクラス変数になります。ここでは、インスタンス変数とクラス変数を総称して属性と呼ぶことにします。Java属性のメタモデルは図22となります。

図22 Java属性メタモデル
  • 可視性を1つ持っている
  • staticの指定が行われていることがある
  • finalの指定が行われていることがある
  • volatileの指定が行われていることがある
  • transientの指定が行われていることがある
  • 型を1つ持っている
  • 属性名を1つ持っている
  • 初期値を持っていることがある 
 Java属性はプログラミング言語上、図23のように記述されます。

図23 Java属性の文法

 可視性は、public、protected、privateおよび表記の省略という4つの指定方法が用意されています。publicが公開、protectedが子孫クラスに公開、privateが公開しない、省略がパッケージ内に公開となっています。

  属性の性質を示す修飾子としてstatic、finalが用意されています。staticが指定されるとクラススコープの属性となります。finalは初期化あるいはコンストラクタ以外で値の設定を許さない属性の指定です。staticとfinalを同時に指定することもできますが、この場合は意味が変わり、定数の指定となり ます。

 volatileとtransientは、属性に対する操作に関する修飾子です。

  volatileは、複数のスレッドから同時にアクセスされた場合に矛盾を起こさない変数であることを示します。通常はvolatileの指定は外れているので、複数のスレッドから同時にアクセスした場合に内容に矛盾が生じても構わないことになります。

  transientは、java.io.ObjectOutputStreamを使ってオブジェクトを直列化する場合に、直列化対象の変数ではないことを示します。通常はtransientの指定は外れているので、オブジェクトの直列化の際には直列化対象となりますが、直列化対象でありながらjava.io.Serializableでないオブジェクトがあった場合には例外が発生します。

4/4

Javaオブジェクトモデリング 第3回
  分類子と“クラス”
  UMLの“クラス”(1)
  UMLの“クラス”(2)
Javaの“クラス”

筆者プロフィール

浅海智晴(あさみ ともはる)

1985年立命館大学電気工学科卒業。同年富士通(株)入社。
UNIXワークステーション/サーバのOS、分散基盤、Web基盤の開発に従事。2001年11月より浅海智晴事務所代表。現在はオブジェクト指向、Java、XMLを中心に活動を行っている。

著書に「Java Super Tips オブジェクト指向設計編」、「XML/DOM Programming」(秀和システム)、
「やさしいUML入門」、「Relaxer - Java/XMLによるWeb開発」、 「XML SmartDoc公式リファレンスマニュアル」((ピアソンエデュケーション)がある。

代表作はJava&XMLベースのオープンソース・ソフトウェアである、
・XML SmartDoc(XML文書処理システム)<http://www.XMLSmartDoc.org>、
・Relaxer(XML/Javaスキーマコンパイラ)<http://www.relaxer.org>。



Javaオブジェクトモデリング INDEX


IT Architect 連載記事一覧

この記事に対するご意見をお寄せください managemail@atmarkit.co.jp

「ITmedia マーケティング」新着記事

「AIによる顧客体験(CX)向上」に懐疑的な見方が広がる――Qualtrics調査
Qualtricsが実施した年次グローバル調査から見えたカスタマーエクスペリエンス(CX)の現...

2025年のSNS大予測 AIの時代に「ソーシャル」はどう変わる?
もういくつ寝ると2025年……と数えるのはさすがに気が早いかもしれないが、それでも2024...

SEOで陥りがちな失敗は「アルゴリズム変更に対応できなかった」が最多に 原因は?
SEOの成功には何が必要なのか、失敗経験者へのアンケートで浮き彫りになったこととは……。