広告

Java : クラスの必要最低限を学ぶ

Java言語でプログラミングするには、クラスは必須となります。
しかし、クラスって意外と難しいですよね。つまづきポイントだと思います。

本記事では、クラスを使うために必要な最低限のことを学び、とにかくコードを書ける下地をつけることを目標とします。

対象読者:変数と基本的な演算(足し算、引き算、代入など) を理解しているかた


概要

オブジェクト指向プログラミングにおけるクラス(英: class)は、オブジェクトを生成するための設計図あるいはひな形に相当するものである。抽象データ型の一つ。クラスから生成したオブジェクトの実体のことをインスタンスという。

クラスはとても奥が深く、そして難しい概念です。
オブジェクト指向プログラミングでは、クラス設計の良し悪しが、そのプログラムの品質に大きく影響します。

熟練のプログラマでも、クラス設計にはいつも頭を悩ませている…と思います。

Java はオブジェクト指向プログラミング言語です。
そして、クラスは必須の概念です。Java を使うからにはクラスから逃れることはできません。

とはいえ、最初からすべてを理解してコードを書くことは難しいです。
習うより慣れろともいいますし、まずは必要最低限のことを学び、とにかくコードを書ける下地をつけましょう。

よって、本記事では 抽象的 なクラスの概念はあまり解説しません。
あくまで 具体的 に使う方法を解説していきます。


クラス

宣言

クラスは、簡単にいうと…

  • フィールド(変数)
  • メソッド(関数)

この2つが集まったものです。

クラス構成

フィールド(変数) は、数値などを保存しておく箱のようなものです。
メソッド(関数) は、プログラムの実際の処理を書きます。例えば、足し算や引き算などの計算をしたり、その結果を画面に出力したり、などなどです。

そんなクラスですが、まずは宣言をしないと使えません。

もっとも単純なクラスを例に、実際のクラス宣言を見てみましょう。

public class Sample {
}

これで、Sample という名前のクラスが宣言できました。
それでは1つ1つの要素を見ていきましょう。

最初の public は アクセス修飾子 です。

public class Sample {
^^^^^^ <--- クラスのアクセス修飾子
}

クラスのアクセス修飾子とは、簡単にいうと…

  • 他のクラスが、この Sample クラスを使えるか? 使えないか?

という制御に使います。

とはいえ、最初のうちはそのあたりを考慮するのは難しいと思います。

クラスのアクセス修飾子は、とりあえず public (公開) と決め打ちして問題ありません。
public は、すべてのクラスが Sampleクラス を使える、という意味になります。

慣れてきたら他のアクセス修飾子を使うことも検討してみましょう。


public class Sample {
       ^^^^^ <--- クラス宣言のためのキーワード
}

次の class は、クラスを宣言しますよ、というキーワードです。
このキーワードがないとクラス宣言ができません。

次に好きなクラスの名前をつけます。

public class Sample {
             ^^^^^^ <--- 任意のクラス名
}

今回は Sample と名づけました。

最後に、カッコ { ... } で囲みます。

public class Sample {
                    ^ <--- クラスの開始
}
^ <--- クラスの終了

このカッコで囲まれた範囲がクラスの中身になります。

今は空っぽですね。

しかし、これでも立派なクラスです。
もちろんコンパイルもとおります。


インスタンスの生成

オブジェクト指向言語においては、多くの場合クラスと呼ばれるものを元に作成したオブジェクトの実体を指す。

さて、クラスは宣言しただけではまだ使えません。
new 演算子を使って、オブジェクトとして生成する必要があります。

このオブジェクトのことを インスタンス とも呼びます。

public class Sample {
}

それでは先ほどの Sample クラスのインスタンスを作成してみます。
整数の変数宣言と比べてみましょう。

// 整数の例
int x = 123;

// クラスの例
Sample sample = new Sample();

クラスの場合は、new 演算子を使うのがポイントですね。
new 演算子の次にクラス名である Sample が続き、最後にカッコ ( ) となります。

Sample sample = new Sample();
^^^^^^ <--- インスタンスの型
Sample sample = new Sample();
       ^^^^^^ <--- 任意のインスタンス変数名
Sample sample = new Sample();
                ^^^ <--- new演算子
Sample sample = new Sample();
                    ^^^^^^ <--- クラス名
Sample sample = new Sample();
                          ^^ <--- カッコ

最後のカッコは、後述する コンストラクタ に関係していますが、今は ( ) としておいてください。

これで、sample という名前のインスタンスが作成できました。
このインスタンスを使って、Sampleクラスにアクセスすることになります。

ただ、Sample クラスの中身は空なので、今はとくになにもできませんが…

ノート

  • Java のクラスは、すべてのクラスが暗黙的に Object クラスを継承しています。
    よって、空っぽのはずの Sample クラスですが、Object クラスのメソッド (例えば toString()hashCode() ) を呼び出すことができます。少し難しい概念なので、とりあえずは気にしなくても大丈夫です。

メソッド

メソッド (method) あるいは メンバー関数 (-かんすう, member function) とはオブジェクト指向プログラミング言語において、あるクラスまたはオブジェクトに所属するサブルーチンを指す。

メソッドとは、プログラムの実際の処理をまとめたものです。
例えば、足し算や引き算などの計算をしたり、その結果を画面に出力したり、などなどです。

Java 以外の言語ではメンバ関数と呼ぶこともあります。

それでは例で見てみましょう。

今回は先ほどまでの Sample クラスではなく、Human クラスを作ります。
Human は 人間 という意味ですね。

public class Human {
    public void say() {
        System.out.println("Hello!");
    }
}

この例では say というメソッドを作りました。
話す という意味のメソッドです。

ノート

  • System.out.println は、文字列や変数の中身をコンソールに表示するためのメソッドです。
    Java の標準ライブラリの1つで、Java の環境さえあれば使えます。
  • なぜインスタンス生成せずにいきなりメソッドを呼び出せるのか? など気になるところはあると思いますが、少々難しいのでとりあえずは コンソールに表示するためのメソッド とだけ覚えておいてください。

呼び出し

それでは Human クラスのインスタンスを生成して、say メソッドを呼び出してみましょう。

Human human = new Human();
human.say();

まず、1行目で Human クラスのインスタンスを生成して human 変数に代入します。
2行目で say メソッドを呼び出します。

このプログラムを実行すると、コンソールには次のように表示されます。

Hello!

無事に say メソッドが実行されたのがわかりますね。

メソッド呼び出しの基本は、

  • インスタンス変数名 + ドット + メソッド名 + カッコ

になります。

human.say();
^^^^^ <--- インスタンス変数名
human.say();
     ^ <--- ドット
human.say();
      ^^^ <--- メソッド名
human.say();
         ^^ <--- カッコ

アクセス修飾子

say メソッドをもう少し詳しく見ていきましょう。

public class Human {
    public void say() {
        System.out.println("Hello!");
    }
}

最初の public は、メソッドのアクセス修飾子です。
クラス宣言 のときにも出てきましたね。

クラスのアクセス修飾子とは違い、メソッドのアクセス修飾子では public (公開) の他に private (非公開) もよく使います。

public void say()
^^^^^^ <--- メソッドのアクセス修飾子

メソッドのアクセス修飾子は、簡単に説明すると…

  • public : 外部からメソッドを呼び出せる
  • private : 外部からメソッドを呼び出せない

という違いがあります。

private メソッドの例を見てみましょう。

public class Human {
    public void say() {
        whisper();
    }

    private void whisper() {
        System.out.println("Hello...");
    }
}

say メソッドは publicwhisper メソッドは private です。
まず publicsay メソッドを呼び出してみます。

Human human = new Human();
human.say(); // コンパイルOK

コンソールには次のように表示されます。

Hello...

whisper メソッドは private ですが、Human クラスの内部(sayメソッド) からは呼び出すことができました。

しかし、Human クラスの外から直接呼び出そうとするとコンパイルエラーになります。

Human human = new Human();
human.whisper(); // コンパイルエラー

さて、private のアクセス修飾子についてどう感じましたでしょうか?
不便だな、と感じるかたもいらっしゃるかもしれません。

しかし、private は無くてはならないアクセス修飾子です。
一般的には、必要最低限のメソッドだけを public にして、それ以外のメソッドは外部からは使えないようにします。

ただ、このあたりはクラス設計の話になってくるので、ちょっと難しいかもです。
慣れるまでは、public をメインで使ってもよいかもしれません。

また、メソッドのアクセス修飾子には publicprivate 以外にもあります。
もし興味がありましたら、下記の記事もご参照ください。


戻り値

アクセス修飾子の次にくるのは 戻り値の型 です。

public class Human {
    public void say() {
        System.out.println("Hello!");
    }
}
public void say()
       ^^^^ <--- 戻り値の型

今回の say メソッドは戻り値がありません。

戻り値がない場合は void とします。
void は「中身がない、空っぽの」という意味ですね。

それでは戻り値のある例も見てみましょう。

Human クラスに、年齢を取得する getAge メソッドを持たせます。

public class Human {
    public int getAge() {
        return 20;
    }
}

戻り値の型は int 型にします。

public int getAge() {
       ^^^ <--- 戻り値の型
}

そして、年齢として 20 を返すようにします。
戻り値を返すには return 文を使います。

public int getAge() {
    return 20;
    ^^^^^^ <--- 戻り値を返す
}

それでは、getAge メソッドを呼び出してみましょう。

Human human = new Human();
int age = human.getAge();

System.out.println(age);

コンソールには次のように表示されます。

20

無事に、getAge メソッドから 20 という値を取得できました。
もちろん int 以外の型を返すこともできます。

自分の名前を返す getName メソッドを追加してみましょう。
getName メソッドは String型を返します。

public class Human {
    public String getName() {
        return "Alice";
    }
}
Human human = new Human();
String name = human.getName();

System.out.println(name);

コンソールには次のように表示されます。

Alice

パラメータ

メソッドにはパラメータを指定することもできます。

say メソッドに、相手の名前を受け取るための yourName パラメータを追加してみましょう。
yourName パラメータは String型にします。

public class Human {
    public void say(String yourName) {
        System.out.println("Hello, " + yourName + "!");
    }
}

パラメータの基本は次のようになります。

  • メソッド名 + ( + パラメータの型 + パラメータ名 + )
public void say(String yourName)
                ^^^^^^ <--- パラメータの型
public void say(String yourName)
                       ^^^^^^^^ <--- 任意のパラメータ名

それでは、パラメータを指定して say メソッドを呼び出してみましょう。

Human human = new Human();
human.say("Bob");

コンソールには次のように表示されます。

Hello, Bob!

無事に、パラメータを指定してメソッドを呼び出すことができました。

パラメータはいくつでも指定できます。
複数指定するには、カンマ(,) で区切ります。

public class Human {
    public void walk(String place, int minutes) {
        System.out.println("place = " + place);
        System.out.println("minutes = " + minutes);
    }
}
Human human = new Human();
human.walk("park", 10);

コンソールには次のように表示されます。

place = park
minutes = 10

フィールド

オブジェクト指向プログラミングでは、フィールドはクラスや構造体などに直接宣言される任意の型の変数であり[3]、オブジェクト内にカプセル化されたデータである。

フィールドとは、クラスのインスタンスが持つ変数のことです。
Java 以外の言語ではメンバ変数と呼ばれることもあります。

今回は Calculator クラスを作ります。
計算機というよりは電卓というイメージです。

まずは、計算の結果を保存するためのフィールドとして result を定義します。

public class Calculator {
    private int result;
}

フィールドの基本は

  • アクセス修飾子 + 変数の型 + 変数名

となります。

private int result;
^^^^^^^ <--- アクセス修飾子
private int result;
        ^^^ <--- 変数の型
private int result;
            ^^^^^^ <--- 任意の変数名

次に、足し算をするための add メソッドと、計算結果を取得する getResult メソッドを定義します。

public class Calculator {
    private int result;

    public void add(int x) {
        result += x;
    }

    public int getResult() {
        return result;
    }
}

それでは、実際に Calculator クラスを使ってみましょう。

Calculator calc = new Calculator();

calc.add(10);
calc.add(20);
calc.add(50);

int result = calc.getResult();

System.out.println(result);

実行した結果、コンソールには次のように表示されます。

80

10 + 20 + 50 = 80 なので、結果が正しいことがわかりますね。


アクセス修飾子

フィールドを定義するには、まずアクセス修飾子を指定します。

public class Calculator {
    private int result;
    ^^^^^^^ <--- フィールドのアクセス修飾子
}

フィールドのアクセス修飾子は private (非公開) にするのが一般的です。
private のフィールドは外部から直接は参照できません。

アクセスしようとするとコンパイルエラーになります。

Calculator calc = new Calculator();
int a = calc.result; // コンパイルエラー

System.out.println(a);

public (公開) にすると外部からも直接参照できます。
ただし、あまり使うことはありません。

public class Calculator {
    public int result;
}
Calculator calc = new Calculator();
int a = calc.result; // コンパイルOK

System.out.println(a);

public にしたほうが便利なのでは?と思うかたもいらっしゃるでしょう。
確かに利便性だけを考えたら public のほうがよいかもしれません。getResult メソッドも不要になりますし…

しかし、private にすることによるメリットもあります。
それは、オブジェクト指向の「情報隠蔽」という考えかたによるものです。

ただ、そのあたりの話は本記事の主眼ではないため割愛します。

もし興味のあるかたは、以下のキーワードで検索してみてください。

  • オブジェクト指向
  • カプセル化
  • 情報隠蔽

また、publicprivate 以外のアクセス修飾子については、下記の記事もご参照ください。


変数宣言

アクセス修飾子の後は、ローカル変数を宣言するのと同じように記述します。
型名 + 変数名ですね。

public class Calculator {
    private int result;
            ^^^ <--- 型名
}
public class Calculator {
    private int result;
                ^^^^^^ <--- 任意の変数名
}

これで int 型の result というフィールドが宣言できました。
ここでは初期値を指定していないので、デフォルトの 0 になります。

int 以外 … 例えば charlong といった他のプリミティブ型の初期値については、下記の関連記事をご参照ください。


StringObject など、プリミティブ以外のデフォルトの初期値は null になります。

public class Human {
    private String name; // 初期値のデフォルトは null です。
}

もし初期値を指定したい場合は次のようにします。

public class Calculator {
    public int result = 100;
}

これもローカル変数に初期値を指定するのと同じですね。

もちろん、複数のフィールドを宣言することもできます。

public class Sample {
    private int x;
    private int y;
    private String name;

    ... 省略 ...
}

インスタンス毎に独立

フィールドの重要な概念として、フィールドの変数は インスタンス毎に独立 して生成されている、ということです。

具体例で見てみましょう。

public class Calculator {
    private int result;

    public void add(int x) {
        result += x;
    }

    public int getResult() {
        return result;
    }
}
Calculator calc1 = new Calculator();
Calculator calc2 = new Calculator();

calc1.add(10);
calc1.add(20);

calc2.add(-30);
calc2.add(-40);

int result1 = calc1.getResult();
int result2 = calc2.getResult();

System.out.println(result1);
System.out.println(result2);

結果は次のように表示されます。

30
-70

Calculator のインスタンスを2つ作ります。(calc1calc2)
そして、それぞれのインスタンスで add メソッドを呼び出します。

calc1 は 10 + 20 = 30 です。
calc2 は (-30) + (-40) = -70 です。

Calculator の result 変数は、calc1calc2 のインスタンスで別々に生成されているのがわかりますね。


コンストラクタ

コンストラクタ(英: constructor)は、オブジェクト指向のプログラミング言語で新たなオブジェクトを生成する際に呼び出されて内容の初期化などを行なう関数あるいはメソッドのことである。

特殊なメソッドの1つとして コンストラクタ があります。
コンストラクタを使うと、new 演算子によるインスタンス生成のときにパラメータを指定できるようになります。

メソッド の解説で使った Human クラスを例にしてみましょう。

public class Human {
    private String name;
    private int age;

    public Human(String n, int a) {
        name = n;
        age = a;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

コンストラクタは次の部分です。

public Human(String n, int a) {
    name = n;
    age = a;
}

ほとんどメソッドと同じですが、

  • コンストラクタの名前は クラス名(Human) と同じ
  • 戻り値の型指定がない

という違いがあります。

それでは Human クラスを使ってみましょう。
使い方は、new 演算子によるインスタンス生成時にパラメータを指定します。

Human human1 = new Human("Alice", 20);
Human human2 = new Human("Bob", 30);

System.out.println(human1.getName() + " : " + human1.getAge());
System.out.println(human2.getName() + " : " + human2.getAge());

結果は次のように表示されます。

Alice : 20
Bob : 30

コンストラクタは、その性質上、インスタンスが生成されるときの 1回 しか呼び出されません。
主な用途としては、そのインスタンスを使うための前準備…つまりフィールドの初期化を行うことが多いのかな、と思います。


補足

staticメソッド

static メソッドとは、クラスのインスタンスを生成しなくても使えるメソッドです。

本記事の主旨である「クラスの必要最低限」の解説に含めるかどうか悩みましたが、軽くだけ触れたいと思います。

具体例を見てみましょう。

public class Sample {
    public static int triple(int x) {
        return x * 3;
    }
}

triple メソッドは、パラメータ x を 3倍した結果を返します。
アクセス修飾子の後ろに static とキーワードを指定しているのが特徴ですね。

static メソッドはインスタンスを生成しなくても、直接メソッドを呼び出すことができます。

int result = Sample.triple(100);

System.out.println(result);

呼び出し方は、

  • クラス名 + ドット + メソッド名 + ( + パラメータ + )

です。

コンソールには次のように表示されます。

300

問題なく triple メソッドが呼び出せました。

static メソッドは、インスタンス化が必要ありません。
つまり、フィールド(変数) が必要ないクラスでは便利になることもあります。

Java の標準ライブラリでもよく使われていますね。

試しに、triple メソッドの static を取り除いてみましょう。

public class Sample {
    public int triple(int x) {
        return x * 3;
    }
}
Sample sample = new Sample();
int result = sample.triple(100);

System.out.println(result);

先ほどとは違い、new Sample() の行が増えました。
わずかですが、手間が増えたことになります。

さて、なぜ補足として static メソッドを解説したかというと、それは Java のプログラムを開始するメソッドに static が必要になるからです。

プログラムの初学者に対して、一番簡単なプログラムを紹介するときに、よく使われる題材に Hello world! をコンソールに出力させる、というものがあります。

実際に、Java で Hello world! を表示させるには次のようにします。

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world!");
    }
}

ここでいきなり、クラスと static メソッドが必要になるのですよね…
Java の Hello world は、他のプログラム言語…例えば Python などに比べて敷居が高いなぁ、と感じてしまいます。

1ファイルに1クラス

Java 言語では、基本的には1つの Javaファイルに1クラスを宣言します。
複数クラスは宣言できません。(できる場合もありますが、ここでは割愛します)

そして、Javaファイル名は、クラス名 + .java となります。
例えば、Sampleクラスを宣言したい場合は、Sample.java ファイルです。

// Sample.java

public class Sample {
}

まとめ

必要最低限といいつつ、けっこうな量になってしまいました…
それだけクラスは難しいということですね。

クラスには、他にも…

  • インタフェース(interface)、抽象(abstract)クラス
  • 継承(extends)、実装(implements)
  • アクセス修飾子 (protected, package private)
  • staticfinal キーワード
  • カプセル化、情報隠蔽、多態性

などなど、重要な概念があります。

とはいえ、一度に理解するのは難しいでしょう。
まずは本記事の内容に慣れてから、次のステップとしてそれらを学習していけたらいいのかな、と思います。


関連記事

ページの先頭へ