クラス

■C言語の構造体
C言語に限らず、多くのプログラム言語では、同じ型のデータ集合を表すには配列を用います。
異なった型のデータの集合を現すにはどうするか?
C言語では構造体を用います。
本の例を挙げれば、「タイトル」、「著者」などは文字列(文字型の配列)で表され、「価格」などは整数型で表されます。この3項目のデータを表す構造体の宣言は以下のようになります。

struct book {
 char title[80];
 char author[80];
 int price;
};

構造体の宣言はいわば設計図なので、この段階ではメモリは確保されません。この構造体を使用するには、以下のようにメモリの確保された実体(ここではmybookとする)を生成してから代入などの操作を行います。

struct book mybook;
strcpy(mybook.title, "宇宙の神秘");
strcpy(mybook.author, "星 陽子");
mybook.price = 2500;

手続き型言語であるC言語でデータ構造を扱う場合はこれで十分でしょう。
その後オブジェクト指向の考え方が言語設計にも適用され大きな成功を収めました。C++やJavaはその代表的な言語です。

■Javaのクラス
●クラスの定義
Javaでも同じ型のデータは配列で表現されます。
異なった型のデータの集合をあらわすには?
この答えはC言語の構造体の単なる延長では表現し切れません。オブジェクト指向の思想に基づいて新しい「クラス」という概念が作られたと理解すべきです。

世界は多くの特徴(attribute)を持つ物(オブジェクト)とそれらの動作(behavior)によって成り立っている。この考えをプログラム言語の設計に取り入れています。物はその特徴を表す(データ、動作、他の物との関係)によって定義されます。プログラム言語でこのような物を表す概念が「クラス」です。現在多く使用されているオブジェクト指向言語C++とJavaはこの「クラス」の概念を同じ記述方法で表現します。

Java言語でのクラス定義の書式は次のとおりです。クラス定義の内部には、オブジェクトのもつデータをクラス内の変数とし、オブジェクトの動作をメソッドとして定義します。

 class クラス名 {
  変数
  メソッド
 }

●メソッドの定義
Java言語では、クラスがもつメソッドをすべてクラス定義の内部に記述します。
もっとも単純なメソッドの書式は以下のとおりC言語の関数と同じです。

 メソッドの型 メソッド名([引数]) {
  メソッドのプログラム
 }

■オブジェクトの生成
クラスは物の概念を表す、ということですが、物の設計図と考えると分りやすいのではないでしょうか。設計図だけではまだ物は出来ていません。プログラムの場合はまだメモリが確保されないのです。クラスを利用するには、まず定義したクラスをもとにオブジェクトを生成します。生成されたオブジェクトをインスタンスと呼びます。

その方法は次の例のとおり、オブジェクトに必要なメモリ領域を確保するnew演算子を使用して行います。
Javaのプログラムとして実行できる例を示しますが、C言語の文化を継承している以上に次のオブジェクト指向の特徴が重要なのです。

・クラスというかたちで、オブジェクトがもつデータと、オブジェクトの動作を定義する。
・クラスをもとにオブジェクトをを生成し、生成されたオブジェクトは、クラスに定義されたデータを持ち、クラスに定義された動作を実行する。
・クラス定義の書式は、上記の例のように、オブジェクトのもつデータをクラス内の変数として定義し、オブジェクトの動作をメソッドとして定義する。
・クラスは変数とメソッドを組にしてカプセル化(Encapusulation)する。
・クラス名を型名として用いることができ、参照型として扱われる(C言語のポインタ型に相当)。

class Book {         // クラス定義の始まり
 String Title;
 String Author;
 int Price;

 void show() {
  System.out.println("タイトル:" + Title);
  System.out.println("著者:" + Author);
  System.out.println("価格:" + Price + "円");
 }
}              // クラス定義の終わり

public class lesson01 {
 public static void main(String[] args) {   // staticについては後述
  Book mybook;                // インスタンスの定義(Cのポインタ宣言相当)
  mybook = new Book();           // オブジェクトの生成(メモリ領域の確保)
  mybook.Title = "宇宙の神秘";      // クラス名と同じ名前のメソッドBook()
  mybook.Author = "星 陽子";      // をコンストラクタと呼ぶ
  mybook.Price = 2500;           // インスタンスの変数に値を代入

  mybook.show();
 }
}

■変数とメソッドのアクセス制限
C言語の改良なら以上のプログラムでもいいでしょう。しかし、これではオブジェクト指向の思想が部分的に取り入れられているにすぎません。
生物を思い浮かべると、個々の細胞は独立した働きを持ち、限定した機能だけで他の細胞と連携して高度な生物一体を作り上げています。単細胞がただ大きくなっただけでは決して実現できないのです。クラスの中の変数が他のクラスから簡単に変更されてしまってはクラスの独立性は確保できません。クラスの中に定義された特別の方法(メソッド)を使わなければデータの取得や変更ができないように設計すべきです。このようにするにはアクセス制御を指定する修飾子(public, protected, private)を使い、変数とメソッドを定義するようにすればよいのです。その例を以下に示します。

class Book {
 private String Title;  // 変数をclass Book内だけからアクセス可能に指定
 private String Author;
 private int Price;

 public void setData(String s1, String S2, int p) {
  Title = s1; Author = s2; Price = p;
 }
 public String getTitle() { // メソッドをclass Book内外からアクセス可能に指定
  return(Title);
 }
 public String getAuthor() {
  return(Author);
 }
 public int getPrice() {
  return(Price);
 }
}

public class Lesson01 {
 public static void main(String[] args) {
  Book mybook;
  mybook = new Book();
  mybook.setData ("宇宙の神秘", "星 陽子", 2500);

  String title = mybook.getTitle(); // ここからclass Bookの変数Titleなどへは
  String author = mybook.getAuthor(); // アクセスできません
  int price = mybook.getPrice();

  System.out.println("タイトル:" + title);
  System.out.println("著者:" + author);
  System.out.println("価格:" + price + "円");
 }
}

これで、オブジェクト指向の思想であるカプセル化が実現されました。他のクラスから変数Title、Author、Priceを直接変更することはできません。
class Bookの使い方は以上の説明のとおりです。しかし、main()のあるclass Lesson01の使用方法はclass Bookと同じようには見えません。Lesson01 mylesson;などの記述がなくどこでインスタンスを生成しているのか分りません。
クラスは新しい概念ですから、その使用方法を習得する必要があります。次の点を理解する必要があります。

・変数とメソッドには2つの種類がある。
1. インスタンス変数とインスタンスメソッド
2. クラス変数とクラスメソッド
・インスタンス変数とインスタンスメソッドはクラスから生成されたインスタンスに属する変数とメソッドである。
・クラス変数とクラスメソッドはクラスに属する変数とメソッドであり、インスタンスを生成しなくともオブジェクトとして使用できる。定義には修飾子staticを使用する。
・複数のクラスからなるファイルの場合、public修飾子は1つのクラスだけに付けられ、そのクラス名をファイル名にする。

C言語プログラミングに慣れていても、クラスを使用始めた頃、使用方法を間違うことがよくあります。例えば、次のような例です。

public class Lesson02 {
 String Title = "宇宙の神秘";

 public static void main(String[] args) {
  System.out.println("タイトル:" + Title);
 }
}

これをコンパイルするとSystem.out.println(..); のところでエラーがでます。
原因は、String型の変数Titleはインスタンス変数として定義されているのでインスタンスを生成しなければアクセスできないのに、main()メソッド内で直接アクセスしているためです。main()メソッドはstatic修飾子が付いていますからクラスメソッドであり、インスタンスを生成しなくとも使用できます。
Titleをクラス変数として定義すれば簡単にエラー解消です。
つまり、2行目をstatic String Title = "宇宙の神秘";と修正するのです。
また、次のようにLesson02クラスのインスタンスを生成する方法もあります。

public class Lesson02 {
 String Title = "宇宙の神秘";

 public static void main(String[] args) {
  Lesson02 obj = new Lesson02();
  System.out.println("タイトル:" + obj.Title);
 }
}