クラスとは

この節の要点

  • クラスとは関係する変数(フィールド)と手続きと操作(メソッド)からなるプログラム構造のことである。
  • クラスそのものは、あくまでどんなフィールドを持ちどんなメソッドを持つかをソースコード上に定義したいわば設計図である。したがって、実際にプログラムで使う際は、その設計内容をメモリ上に形にしたものをプログラムが扱う。クラスを元に作成したメモリ上のプログラム構造をインスタンスあるいはオブジェクトと呼ぶ。
  • クラスからオブジェクトを作成する際は**new**キーワードを使う。
  • クラスを設計する際は、現実世界の概念と対応付けて設計させることが多く、その際はクラスが概念に、インスタンスやオブジェクトがその概念の実例に対応する。
  • static修飾子が付いていないメソッドをインスタンスメソッドと呼ぶ。インスタンスメソッドはオブジェクトを介して呼び出すメソッドである。
  • クラス内に定義されたフィールドやメソッドの定義時に前置されたpublicをアクセス修飾子と呼ぶ。

\({\Huge``}\) Any useful concept has some degree of generality, i.e. it is a \({\it class}\) of specialised instances. In other words one tries to group phenomena occurring in a dynamic system into \({\it classes}\) of phenomena and to describe each class by a single piece of program. \({\Huge,\hspace{-0.4em},}\)

------ Ole-Johan Dahl, C. A. R. Hoare, III Hierachical Program Structures, p.177[7]

\({\Huge``}\) 有用な概念はどれも、ある程度の一般性をもつものである。すなわち、それは特殊な実例(instance)が集まったクラス(class)なのである。いい換えると、動的システムに現れる現象を、現象のクラスとしてひとまとめにし、それぞれのクラスをプログラム部分として記述しようというのである。\({\Huge,\hspace{-0.4em},}\)

------ オーレ・ヨハン・ダール, トニー・ホーア, III 階層的プログラム構造. p.199[7]

基本的にクラス構造は以下の2つのプログラム構造から成ります。

  • 概念を表すために必要となるデータ構造(変数群)
  • 概念の振る舞いを表すための手続き・関数群

このクラス構造はC言語で(強引に)例えるのであれば、ある構造体にその構造体に関係する手続きや関数を付け加えたものと考えてください。 このクラスを中心とした設計手法は、今日に至るまで様々な言語においてより設計が便利になるように概念が拡張と洗練がなされてきました。

クラスオブジェクトのみでプログラムが構成されるプログラミング言語であるSmalltalkや、初めての実用的なクラス設計が可能となった言語であるC++(とその前身であるC with Classes)は、特にSimula 67の大きな影響を受けています[12]。本演習で利用するJavaは、これら言語のうち、C++の設計思想上に位置します。

Javaにおけるクラスとはどのようなものか、クラスの解説は第1週で説明した内容と重複しますが、以降であらためて解説します。

public class User {

	public String familyName;
	public String firstName;

	public String getUserName() {

		return familyName + " " + firstName;
	}
}
図3:Javaにおけるクラスの例、ユーザデータを表すUserクラス
public static void main(String[] args) {
	// クラス定義からオブジェクトの作成
	User u = new User();

	// クラスのフィールドへの代入
	u.familyName = "Tanaka";
	u.firstName = "Taro";

	// クラスのメソッドの利用
	String uname = u.getUserName();

	System.out.println(uname);
}
図4:図3を呼び出すためのmainメソッド例

図3にクラスの例を示します。図3のUserクラスは、なんらかのユーザ情報の概念化した例です(図5)。

ユーザ情報の概念とソースコードへの対応付け

図5:ユーザ情報の概念とソースコードへの対応付け

図4における3行目にて、図3で定義されたクラスUserに言及して図6のように書き下されています。

User u = new User();
図6:クラス定義からインスタンスの作成例

これは、Userという概念(クラス)から、新しく実例(インスタンス)をnew することで作成し、変数uに作成した実例を割り当てた(図7)、と解釈できます。

概念と実例(ユーザ情報の概念の場合)

図7:概念と実例(ユーザ情報の概念の場合)

誤解を恐れずに例えるならば、クッキーの型をクラスとすると、その型を使って大きなクッキー生地(メモリ空間)から切り出した(newした)、型の形をしたクッキー生地(確保したメモリ領域)がインスタンスです。先に述べたオブジェクトは、このクラスの実例であるインスタンス1と同じ意味で使われることが多いです。

ここで、Userクラスは、int型やString型などと同じで、User型を表しており、基本的にUser型インスタンスはUser型変数にしか代入できません。

図3に定義されているクラスは変数(フィールド)と手続きや関数(メソッド)を中に含んでいます。

ここで定義されているメソッドは、これまでの各週のプログラムでクラス内に定義したメソッドと異なり、クラスメソッド(static修飾子が付けられたメソッド)ではありません。このようなメソッドをインスタンスメソッド と呼びます。

このインスタンスメソッドは、読んで字のごとく、オブジェクト(インスタンス)から呼び出すことができるメソッドです。従って、クラスから直接呼び出すことはできません。 例えば、図4の6行目、7行目、10行目に示すように、3行目で作成したオブジェクト(インスタンス)から、呼び出していることがわかります。

基本的にクラス構造を使ったプログラムは、以下の流れが入れ子構造になることで形作られることに注意してください。

  1. クラスからオブジェクト(インスタンス)作成
  2. オブジェクト(インスタンス)を介してメンバーやメソッドを呼び出す

ここで、図3のプログラムを見ると、3行目や4行目の変数や6行目のメソッドの前にpublicと呼ばれる修飾子がついていることが分かるはずです。この修飾子は図8で示すようなフィールドやメソッドのシグネチャで利用され、アクセス修飾子と呼ばれます。

publicアクセス修飾子によるフィールドやメソッドのシグネチャ

図8:publicアクセス修飾子によるフィールドやメソッドのシグネチャ

アクセス修飾子については、詳細は次の節で説明しますが、少なくともpublicとなっている変数やメソッドは、図9で示すように、クラス外の別メソッドから、作成したオブジェクト(インスタンス)に対して.(ピリオド)を介することで、C言語の構造体のメンバーと同様に、変数の値を取得したり、メソッドを呼び出したりしてメンバーを利用することができます。

// オブジェクトのフィールドへの代入
u.familyName = "Tanaka";
u.firstName = "Taro";

// オブジェクトのメソッドの利用
String uname = u.getUserName();
図9:図4のUserクラスを使った処理におけるインスタンスフィールドおよびインスタンスメソッドの呼び出し箇所

[7]: エドガー・ダイクストラ, トニー・ホーア, オーレ・ヨハン・ダール, ``構造化プログラミング'', サイエンス社 (1975)

[12]: B. Stroustrup, ``C++の設計と進化'', ソフトバンクパブリッシング (2005)


1

定義に揺れがありますが、オブジェクトはクラスから作り出した概念上のものを含む実例であり、インスタンスはクラスから作り出した実例の実際のメモリ上のデータ構造を指します。まとめるとオブジェクトのうち特にメモリ上にあるものを指し示したい時、インスタンスと呼びます。