クラス

Java基礎 6

1.本章での学習項目

本章では、Java言語の中で、最も重要なクラスについて学習します。

2.本章の講義1

本章で学習する内容を動画としてまとめたものです。最初に一通り見終わった後で、学習に入るようにしてください。

講義:クラス①

3.クラス

クラスは、Java言語の中で最も重要な文法と言っても良いでしょう。
クラスを理解することは、Javaプログラミングの本当の第一歩となります。

これからクラスの概要とプログラミングについて学習していきますが、
学習のポイントとしては、サンプルソースを書き写して動かしてみることです。

プログラミングは、ソースをただ眺めているだけでは上達しません。
プログラムを実際に動かしながら、その処理がどのような手順で行われているかを理解するようにしましょう。

3.1.クラスとは

クラスとは、Javaプログラムそのものです。Javaでは、プログラムを全て「クラス」で表現します。
クラスは、以下のように「class クラス名{・・・}」で書かれるひとまとまりのプログラムのことです。


classunit

Javaで構成されたシステムやソフトウェアは、いくつものクラスで成り立ち、各クラスは相互にやりとりをしながら処理が進んでいきます。


sougosayo

Javaは、オブジェクト指向言語という言語です。
オブジェクト指向言語であるJavaの特徴の一つとして、上記で説明したように、いくつかのクラスの相互やりとりによって、一連の処理が実行されます。
クラス同士が相互にやりとりをしていきながら一連の処理が実行されますが、その中で実行の起点となるクラスが存在します。
これ以降、この実行の起点となるクラスを「利用するクラス」と呼びます。

Javaでは、利用するクラスが他のクラスのデータ(値)や処理を利用しながら、自身の処理を実行していきます。
利用されるクラスは、例えば計算処理を行って、その結果を利用するクラスに返したり、
データベースからデータを取得して、そのデータのセットを返したり・・・と何らかの処理を行ってくれたりします。

利用するクラスは、自身には記述されていなくとも、他のクラスの処理を利用することにより、処理を進めることができるのです。
このように、お互いに処理を利用することで、重複した処理は、何度もプログラムを書かず、効率的にプログラミングを行うことができます。


sougosayo2

4.クラスの構成

それでは、クラスの基本構成を説明します。
クラスの基本構成は、クラスの名前、属性(値)、操作(処理)の3つで成り立っています。

クラスの名前は、今まで定義してきたように「public class XX・・・」と記述されたXXの部分です。クラスを作成する場合は、必ず必要となります。
属性(値)とは、そのクラスが持つデータ(値)で、データ(値)を代入された変数をフィールドと呼びます。
操作(処理)は、計算処理やデータベースからデータを取得するなど、何らかの処理が定義された部分で、メソッドと呼びます。
フィールドとメソッドは、クラスのメンバと呼びます。


classkousei

クラスには、クラス名が必ず必要となりますが、フィールドとメソッドは記述しなくてもエラーにはなりません。
通常、利用するクラスは、他のクラスのフィールドにアクセスしてそのデータ(値)を利用したり、メソッドにアクセスして何らかの処理をし、その結果を受け取ったりといったやりとりが発生します。クラスの利用の仕方は、後述します。

それでは、フィールドとメソッドを詳しく説明していきます。

4.1.フィールド

まずは、フィールドから説明します。
フィールドは、変数です。変数は、すでに学習したように、データ(値)を格納することができます。
フィールドと呼ばれる変数は、クラスブロック内(クラスの「{}中括弧」の中)で宣言され、フィールドに格納されたデータ(値)は、クラス全体で有効になります。

クラスやif文、for文など色々な「{}中括弧」がありますが、どの「{}中括弧」の中で書かれたかにより、有効範囲が変わります。
これを変数のスコープと呼びます。
フィールドとして宣言された変数は、他のクラスから利用されることができるようになります。
サンプルでは変数に簡易的な名前(xやyなど)を付けていますが、実際の開発では、どんな値を格納するための変数なのか、一目で分かるような名前にすることが大切です。覚えておきましょう。

フィールドの定義は、以下のような書式になります。定義の仕方は、変数の宣言の仕方と同じです。

public class クラス名 {
	フィールドxの定義;
	フィールドyの定義;
}

プログラムで書くと、以下のようになります。

public class FieldClass {
	int x; // フィールドxの定義
	String y; // フィールドyの定義
}

フィールドについての説明は、簡単ですが、以上です。

Information

変数のスコープとは

変数の有効範囲というものがあります。それを、変数のスコー プと呼び、変数を扱うときには、よく理解しておく必要があります。
変数は、「{}」で囲まれた中で定義をすると、その囲まれた中でのみ有効となります。その外側では、使用することができません。
括弧内の処理が終了すると、その変数はアクセスできないだけではなく、やがてメモリー上からも消えてしまいます。

フィールドは、クラスの「{}」の中で有効となります。フィールド以外の変数は、ローカル変数と呼ばれます。
ローカル変数は、初期化をせずに使うとエラーになります。使用する前に必ず値を代入しなければいけません。


scope

4.2.メソッド

次にメソッドを学習します。

メソッドとは、計算やデータベースからデータの取得など、何らかの処理が切り出された部分です。
その一まとまりの処理にメソッド名をつけ、そのメソッドがあるクラス、もしくは、他のクラスから利用できるようにします。

4.2.1.メソッドの定義

メソッドの定義は、以下のとおりです。ただし、定義順序は、必ずしもこのとおりではありません。

  1. メソッド名の定義
    まず、メソッドの名前を付けます。メソッドの名前は任意ですが、Javaの命名規則がありますので、予約語などは使用しないよう気をつけましょう。
    また、変数と同様に、メソッドもサンプルでは簡易的な名前を付けていますが、実際の開発では、どんな処理を行うのか一目で分かるような名前にすることが大切です。


    methodname

  2. 引数用()の記述
    メソッドの名前の後ろには、「() 括弧」を書きます。この括弧は、引数で使用しますが、詳細は後述します。


    methodkakko

  3. 処理用の{}と処理の記述
    「() 括弧」の後は「{} 中括弧」を書き、この中括弧の中にメソッドの処理を書きます。
    メソッドの処理は、計算処理やデータベースからデータの取得など様々な処理となります。
    そして、通常、一番最後にreturn文という構文を記述します。
    このreturn文は、計算やデータベースから取得したデータなど処理した結果のデータ(値)を、呼び出し元である利用するクラスに戻します。
    これを戻り値と呼びます。戻り値の詳細は、後述します。


    methodkakko2

  4. 戻り値の型の定義
    メソッドは、メソッドの名前の前に、戻り値の型を定義する必要があります。


    methodkata

メソッドの書式をまとめると、以下のようになります。

戻り値の型 メソッド名(引数リスト) {
	処理;
	return文;
}

メソッドの記述のサンプルソースです。「getSum」というメソッド名で、処理は、int型の変数sumに1+2+3の結果6を代入し、その変数sumの値6を戻り値として戻しています。
戻り値がint型なので、メソッド名「getSum」の前は、「int」を記述します。


method

4.2.2.void

さて、メソッドには戻り値を利用するクラスに戻すreturn文が最後に記述され、メソッド名の前に戻り値の型を定義すると説明しました。
しかし、戻り値がないケースもあります。例えば、データベースにデータを登録する処理で、
結果を何も戻す必要がない場合や、メソッドの処理の中で結果をコンソールに出力(System.out.println())すれば良い場合などです。
このような処理の場合には、戻り値が必要ないため、メソッド名の前に戻り値の型には、voidを記述します。

戻り値がない場合のメソッドの書式は、以下のとおりです。

void メソッド名(引数リスト) {
	処理;
}

戻り値がない場合のメソッドの記述のサンプルソースです。


methodvoid

メソッドの利用については、後述します。まずは、利用されるクラスでフィールドやメソッドの定義方法を復習します。

4.3.利用されるクラスの定義

利用されるクラスの定義は、クラスの名前、フィールド、メソッドをそれぞれ以下のように定義します。
戻り値ありの場合と戻り値なしの場合の2パターンを説明します。どちらも実行するクラスではありませんので、これらのクラスは、実行できません。

まず、戻り値ありの場合のサンプルソースです。

ClassStudy1.java
public class ClassStudy1 { // クラスの宣言

	int x = 10; // フィールドxの宣言と代入

	int getSum() { // getSumメソッドの定義(戻り値はint型)
		int sum = 1 + 2 + 3; // ローカル変数sumに1+2+3の結果を代入
		return sum; // sumを呼び出し元クラスにreturn
	}
}

次に戻り値なしの場合のサンプルソースです。

ClassStudy2.java
public class ClassStudy2 { // クラスの宣言

	int x = 10; // フィールドxの宣言と代入

	void printSum() { // printSumメソッドの定義(戻り値なし)
		int sum = 1 + 2 + 3; // ローカル変数sumに1+2+3の結果を代入
		System.out.println(sum); // sumをコンソールに出力
	}
}

どれがフィールドで、どれがメソッドか、すぐに分かったでしょうか。分からないようでしたら、再度復習しましょう。

5.本章の講義2

本章で学習する内容を動画としてまとめたものです。最初に一通り見終わった後で、学習に入るようにしてください。

講義:クラス②

6.クラスの利用

それでは、利用するクラスの定義方法について学習しましょう。
利用するクラスも、利用されるクラスと同様に、クラス名、フィールド、メソッドで構成されますが、実行の処理をするためには、メインメソッドという特別なメソッドが必要になります。

まずは、メインメソッドについて、学習します。

6.1.メインメソッド

これまで、実行するクラスを作成するときには、必ずクラスの宣言の後に、「public static void main(String[] args){・・・}」という記述をしていました。
実は、これが実行するクラスに必要なメインメソッドです。
このメインメソッドがあるクラスだけが、実行できるクラスです。
実行の操作をすると、まずメインメソッドのところから処理が始まるようになっています。
実行する必要がなく、利用されるだけのクラスは、このメインメソッドを記述する必要はありません。

メインメソッドのメソッド名は、「main」となります。「void」は、先ほど説明したとおり、戻り値がないという意味です。「public」と「static」の記述については、また後程学習します。


mainmethod

6.2.クラスの宣言とインスタンス化

メインメソッドから処理が始まり、他のクラスを利用する場合、クラスの宣言とインスタンス化という手続きが必要です。

書式は、以下のようになります。

利用したいクラス名 参照変数名 = new 利用したいクラス名();

プログラムで書くと、以下のとおりとなります。先ほど利用されるクラスで作成した「ClassStudy1」クラスをインスタンス化しています。

RiyoClass.java
public class RiyoClass {
	public static void main(String[] args) { // メインメソッド
		ClassStudy1 cs1 = new ClassStudy1(); // クラスの宣言とインスタンス化
	}
}


instance

それでは、この記述の左辺から説明します。左辺は、クラスの宣言部です。変数の宣言を思い出してください。
「int x」のように、データ型と変数名で宣言する必要がありました。他のクラスを利用するときも同様の宣言が必要になります。
上記のサンプルで見ると、「ClassStudy1」がクラスの型で、「cs1」が変数名です。
型がクラスの型の場合、その型で定義された変数を参照変数と呼びます。定義されたクラスは、あくまでも型であり、実際に利用するときには、変数として宣言する必要があります。

次に、右辺の説明です。右辺は、インスタンス化ということを行っています。
インスタンス化とは、変数の初期化と同様です。変数は、宣言をしても初期化をしていないと使用できません。
初期化されることにより、変数用のメモリがきちんと確保されるためです。
そのため、何かが代入されて初めて、使用することができます。

インスタンス化は、初期化と同様「newクラス名()」をすることで、そのクラスの型のメモリが準備されます。
このメモリが準備されることを「実体を持つ」と呼んだりします。
また、クラスの型に基づいて実体を持ったクラスの変数をオブジェクトと呼びます。
他のクラスを利用するときは、このインスタンス化を行い、実体を持ったオブジェクトを変数に代入することにより、そのクラスのフィールドやメソッドを利用することができます。

6.3.フィールドとメソッドの利用

さて、クラスのインスタンス化をした後は、フィールドやメソッドを利用することができるようになります。
どのように利用するかを説明します。

まず最初に、フィールドの利用です。フィールドの利用は、以下の書式となります。
先ほどつけたクラスの変数名に「.(ドット)」、そして利用したいフィールド名を記述します。

参照変数名.フィールド名;

次にメソッドの利用です。メソッドの利用は、以下の書式となります。メソッドの利用も、クラスの変数名に「.(ドット)」、メソッド名を記述します。

参照変数名.メソッド名();

フィールドもメソッドも、クラスの宣言で定義した参照変数名に「.(ドット)」を記述し、フィールド名、メソッド名と記述するという点では、似たような記述の仕方となります。
ただし、メソッドの場合は、メソッド名の後に必ず「() 括弧」を付けましょう。


fieldmethod

フィールドとメソッドの利用のプログラムは、以下のとおりとなります。
利用されるクラスで定義した「ClassStudy1」クラスをインスタンス化し、そのクラスに定義されていたフィールド「x」とメソッド「getSum」を利用しています。

RiyoClass.java
public class RiyoClass {
	public static void main(String[] args) {
		ClassStudy1 cs1 = new ClassStudy1(); // クラスの宣言とインスタンス化
		int y = cs1.x; // ClassStudy1クラスのフィールドxの利用
		int z = cs1.getSum(); // ClassStudy1クラスのメソッドgetSum()の利用
	}
}

6.4.利用するクラスの定義

それでは、利用されるクラスと利用するクラスの定義を復習しましょう。
まず、利用されるクラスのサンプルソースを確認してください。

ClassStudy1.java
public class ClassStudy1 {
	// フィールドxの宣言と代入
	int x = 10;

	// getSumメソッドの定義(戻り値は、int型)
	int getSum() {
		// ローカル変数sumに1+2+3の結果を代入
		int sum = 1 + 2 + 3;

		// sumを呼び出し元クラスにreturn
		return sum;
	}
}

次に利用するクラスのサンプルソースです。

RiyoClass1.java
public class RiyoClass1 {
	public static void main(String[] args) {
		// クラスの宣言とインスタンス化
		ClassStudy1 cs1 = new ClassStudy1();

		// ClassStudy1のフィールドxを利用し、その値10を出力
		System.out.println(cs1.x);

		// ClassStudy1のメソッドgetSumを利用し、変数sumの値6を出力
		System.out.println(cs1.getSum());
	}
}

「cs1.x」は、ClassStudy1クラスの変数xを利用しているため、その変数xの値10が取得できます。
「cs1.x」をそのままコンソールに出力すると、10が表示されます。
「cs1.getSum()」は、ClassStudy1クラスのメソッド「getSum()」を利用しています。
メソッド「getSum()」は、変数sumの値(1+2+3=6)が戻り値として戻されるので、6が取得できます。
そのため、「cs1.getSum()」をそのままコンソールに出力すると、6が表示されます。

もう一つ、利用するクラスのサンプルソースを見てみましょう。

RiyoClass2.java
public class RiyoClass2 {
	public static void main(String[] args) {
		// クラスの宣言とインスタンス化
		ClassStudy1 cs1 = new ClassStudy1();

		// ClassStudy1のフィールドxを利用し、その値10を変数yに代入
		int y = cs1.x;

		// ClassStudy1のメソッドgetSumを利用し、変数sumの値6を変数zに代入
		int z = cs1.getSum();

		//「cs1.xは、10です」を出力
		System.out.println("cs1.xは、" + y + "です");

		// 「cs1.getSum()は、6です」を出力
		System.out.println("cs1.getSum()は、" + z + "です");
	}
}

このサンプルソースでは、「cs1.x」の10の値をそのまま変数yに代入しています。
また、「cs1.getSum()」も同様に変数zに代入しています。
このように、取得した値を利用するクラスで変数に代入して利用することもできます。

利用するクラスと利用されるクラスの定義は以上です。

7.戻り値と引数

それでは、戻り値(もどりち)と引数(ひきすう)について、説明します。

戻り値と引数は、利用するクラスと利用されるクラスの間でやりとりされるデータ(値)です。
クラス同士でデータ(値)がやりとりされることによって、お互いの処理が進んでいきます。

戻り値は、利用されるクラスから利用するクラスに渡されるデータ(値)です。
引数は、利用するクラスから利用されるクラスに渡されるデータ(値)です。


hikisu

7.1.戻り値

まずは、戻り値の学習です。

メソッドの中にreturn文を記述することによって、利用するクラスに戻り値としてデータ(値)を受け渡します。
return文の後ろに、呼び出し元へ戻したいデータ(値)を記述します。
基本データ型の変数でもクラス型の参照変数でも、戻り値とすることができます。

以下は、サンプルソースです。sumの値(6)が戻り値となります。

ClassStudy1.java
public class ClassStudy1 {
	// フィールドxの宣言と代入
	int x = 10;

	// getSum()メソッドの定義(戻り値は、int型)
	int getSum() {
		// ローカル変数sumに1+2+3の結果を代入
		int sum = 1 + 2 + 3;

		// sumを呼び出し元クラスにreturn ←sumが戻り値
		return sum;
	}
}

7.2.引数

次に引数を学習します。

メソッドの実行時に利用されるクラスへ引数を引き渡すには、メソッドの名前の後ろにある「() 括弧」の中にデータ(値)を記述します。
「() 括弧」の中に複数の引数を記述することによって、複数のデータ(値)を引き渡すこともできます。

まず、利用されるクラスの定義をします。
利用するクラスから引き渡されてくる引数を受け取れるように、メソッド名の後ろの「() 括弧」に、変数を定義します。

メソッド名(型 変数1, 型 変数2, 型 変数3・・・)

利用されるクラスのサンプルソースです。int型の変数iとjをメソッド名の後ろの括弧に定義し、データ(値)を引き受けられるようにしています。

public class HikisuStudy {
	// フィールドxの宣言と代入
	int x = 10;

	// getResultメソッドの定義(引数として引き受ける変数を定義)
	int getResult(int i, int j) {
		// ローカル変数resultにx(10)+i*jの結果を代入
		int result = x + i * j;

		// resultを呼び出し元クラスにreturn
		return result;
	}
}

次に利用するクラスからの引数の引渡し方です。利用するクラスで、メソッドを利用するときには、メソッド名の後ろの「()(括弧)」に引き渡すデータ(値)を記述します。

参照変数名.メソッド名(引数1、引数2、引数3・・・)

利用するクラスのサンプルソースです。
利用されるクラスをインスタンス化した後に、「hs.getResult(10, 20)」と記述し、10と20の値を引き渡しています。
10は、利用されるクラスの変数iに、20は、jにそれぞれ引き渡されます。

RiyoHikisuClass.java
public class RiyoHikisuClass {
	public static void main(String[] args){// メインメソッド
		// クラスの宣言とインスタンス化
		HikisuStudy hs = new HikisuStudy();

		// getResultメソッドを利用(10と20を引数として引き渡す)
		// 引数として値の引渡し、x(10)+i(10)*j(20)の結果210が戻り値
		int y = hs.getResult(10,20);

		// 変数y(210)を出力
		System.out.println(y);
	}
}

引数のポイントは、引き渡す側の引数の数と型、引き受ける側の引き受け変数の数と型を、一致させる必要があるということです。
一致していないとエラーとなりますので、注意しましょう。

7.3.戻り値と引数

それでは、以下の図で、引数と戻り値のやりとりを再度復習しましょう。


hikisu2

7.4.自身のメソッドを呼び出す

同じクラスにあるメソッドを呼び出す方法です。他のクラスと同様に、最初にそのクラス自身をインスタンス化し、メソッドを呼び出します。

以下がサンプルソースです。

AverageTest.java
public class AverageTest {
	public static void main(String[] args) {
		// クラス宣言とインスタンス化
		AverageTest aveTest = new AverageTest();

		// average()メソッドを利用(40と80と70を引数として引き渡す)
		int avr = aveTest.average(40, 80, 70);
		System.out.println("平均 = " + avr);
	}

	// 引数で渡された値(40, 80, 70)の平均値を求めて返却
	int average(int firstargs, int secargs, int thirdargs) {
		int avr = (firstargs + secargs + thirdargs) / 3;
		return avr;
	}
}

戻り値と引数の学習は、以上です。
戻り値と引数は、利用するクラスと利用されるクラスのやりとりにおいて、重要なポイントです。よく理解するようにしましょう。

8.練習問題1

利用するクラス、利用されるクラスの練習です。

8.1.問題1

下記クラス(Greeting1.java)のdisplayメソッドを呼び出す(利用する)クラスを作成しましょう。
なお新たに作成するクラス名は問いません。

Greeting1.java
public class Greeting1 {

	void display() {
		String greet = "おはようございます";
		System.out.println(greet);
	}

}

SampleMain1.java
public class SampleMain1 {

	public static void main(String[] args) {
		Greeting1 greeting = new Greeting1();
		greeting.display();
	}

}

利用するクラスとしてSampleMain1クラスを定義し、mainメソッドを設定しました。
mainメソッドではGreeting1クラスをインスタンス化(new Greeting1()の部分)することで、
Greeting1クラスのdisplayメソッドを使用できるようにしています。

8.2.問題2

続いては下記クラス(SampleMain2.java)のmainメソッドが呼び出す(利用される)クラスを作成しましょう。

SampleMain2.java
public class SampleMain2 {

	public static void main(String[] args) {
		Greeting2 greeting = new Greeting2();
		// displayメソッドはコンソールに「こんにちは」と表示させるメソッドとする
		greeting.display("こんにちは");
	}

}

Greeting2.java
public class Greeting2 {

	void display(String greet) {
		System.out.println(greet);
	}

}

当設問ではSampleMain2クラスがGreeting2クラスをインスタンス化し、displayメソッドを呼び出しています。
そのため作成するクラスはクラス名:Greeting2, メソッド名:displayである必要があります。
またdisplayメソッドは引数としてString型の「こんにちは」を渡されていますので、
作成する利用されるクラスでは引数を受け取れるよう設定する必要があります。
ここでは単純に受け取った文字列をそのままコンソールに表示させるだけですので、
受け取った引数(String greet)をそのままSystem out println()に渡しています。

8.3.問題3

続いては下記クラス(SampleMain3.java)のmainメソッドが呼び出す(利用される)クラスを作成しましょう。

SampleMain3.java
public class SampleMain3 {

	public static void main(String[] args) {
		Greeting3 greeting = new Greeting3();
		String sentence = greeting.display("こんにちは","TechFun");
		// 「こんにちはTechFunさん」とコンソールに出力されるようにしましょう
		System.out.println(sentence);
	}

}

Greeting3.java
public class Greeting3 {

	String display(String greet, String name) {
		return greet + name + "さん";
	}

}

SampleMain3クラスから作成すべきクラス及びメソッドは次のように決まります。
クラス名:Greeting3
メソッド名:display
引数:(String型その1, String型その2)
戻り値の型:String型
またコメントから利用されるクラスでは「String型その1+String型その2+さん」というsentenceを生成しなければならないことが分かります。
以上より解答の通り、return文でsentenceに該当する部分を返却するようなメソッドとなります。

9.コンストラクタ

コンストラクタは、フィールドを初期化する特別なメソッドです。利用されるクラスで定義します。

9.1.コンストラクタの定義

コンストラクタは、フィールドを初期化するための特別なメソッドであるため、戻り値は、定義しません。
また、戻り値がないので、メソッド名の前に戻り値の型、もしくはvoidを書く必要もありません。
コンストラクタの名前は、必ずクラスと同じ名前で定義します。

以下がコンストラクタの書式となります。

コンストラクタ名(クラスと同じ)(型 変数1, 型 変数2, 型 変数3・・・)

コンストラクタを使ったサンプルソースです。
利用されるクラスで、クラスと同じ名前のメソッドとして定義します。
その処理で、フィールドを初期化します。

ConstructStudy1.java
public class ConstructStudy1 {
	int x; // フィールドxの宣言

	ConstructStudy1() { // コンストラクタ
		x = 10; // xを10で初期化
	}

	int getX() { // getXメソッドの定義
		return x; // xを呼び出し元クラスにreturn
	}
}

9.2.コンストラクタの利用

それでは、利用するクラスで、利用されるクラスのコンストラクタを呼び出す方法を説明します。

コンストラクタの利用は、今までインスタンス化で記述してきた「new クラス名()」で利用できます。
インスタンス化をすると、利用されるクラスのコンストラクタが実行され、クラスのオブジェクトが生成されます。
以下が利用するクラスのサンプルソースです。インスタンス化している「new ConstructStudy1()」の記述の部分で、利用されるクラスのフィールドxが10で初期化され、オブジェクトが生成されます。

RiyoConstruct1.java
public class RiyoConstruct1 {
	public static void main(String[] args){
		// クラスの宣言とインスタンス化(このときに変数xが10で初期化される)
		ConstructStudy1 cs1 = new ConstructStudy1();

		// getXメソッドを利用(戻り値10が変数yに代入される)
		int y = cs1.getX();

		// 変数y(10)を出力
		System.out.println(y);
	}
}

以下が、利用するクラスと利用されるクラスのやりとりを説明した図になります。理解できたでしょうか。


construct1

さて、コンストラクタは、メソッドであることから、引数を引き渡すことも可能です。
コンストラクタ名の後の「() 括弧」を使用して、引数を引き渡します。

以下が利用されるクラスのサンプルソースです。
コンストラクタ「ConstructStudy2」の「()」に引数として「int i」を記述しているため、このコンストラクタはint型のデータ(値)を一つ引き受けることができます。

ConstructStudy2.java
public class ConstructStudy2 {
	int x; // フィールドxの宣言

	ConstructStudy2(int i) { // コンストラクタ
		x = i; // xを変数iで初期化
	}

	int getX() { // getXメソッドの定義
		return x; // xを呼び出し元クラスにreturn
	}
}

そして、以下が利用するクラスのサンプルソースです。
「ConstructStudy2」クラスをインスタンス化(new以降の記述部分です)するときに、「new ConstructStudy2」の「()」の中に引数を記述します。

以下の例では、20を引き渡しています。20を引数として引き渡してインスタンス化をすると、利用されるクラスのコンストラクタ「ConstructStudy2(int i){・・・}」につながります。
そのあと、「int i」に20が代入され、最終的にフィールドxにその20が代入されて、初期化されます。
「getX」メソッドを利用すると、変数xの値(20)が戻ってきます。

RiyoConstruct2.java
public class RiyoConstruct2 {

	public static void main(String[] args) {
		// クラスの宣言とインスタンス化(変数xが20で初期化されます)
		ConstructStudy2 cs2 = new ConstructStudy2(20);

		// getXメソッドを利用(戻り値20が変数yに代入されます)
		int y = cs2.getX();

		// 変数y(20)を出力
		System.out.println(y);
	}
}

以下が、引数がある場合の利用するクラスと利用されるクラスのやりとりを説明した図になります。


construct2

コンストラクタは、今まで定義してきませんでしたが、利用するクラスで利用されるクラスのインスタンス化をすると、問題なくインスタンス化を実行することができていました。
これは、コンストラクタが定義されていない場合、引数なしのコンストラクタがコンパイル時に自動的に生成されるようになっているからです。
利用するクラスは、利用されるクラスをインスタンス化したときに、そのクラスのコンストラクタにアクセスしているのです。
では、引数ありのコンストラクタのみ定義されていた場合は、どうでしょうか。
この場合は、引数ありのコンストラクタのみが生成されますので、利用するクラスは、利用されるクラスをインスタンス化するときに、必ず適正な引数の値をそのクラスのコンストラクタへ引き渡す必要があります。

以上で、コンストラクタの学習は終わりです。

10.練習問題2

クラスの練習問題です。
利用されるクラスと利用するクラスの基本的な記述について確認していきましょう。

10.1.問題1

まずは、利用されるクラスの定義についての問題です。
以下の指定通りにSeiseki1クラスを記述しましょう。

表 1. Seiseki1クラス
クラス Seiseki1
フィールド String name 生徒の名前
int kokugo 国語の点数
int sugaku 数学の点数
int eigo 英語の点数
コンストラクタ Seiseki1() 下記内容で各フィールドを初期化する

  • name = "山田"
  • kokugo = 100
  • sugaku = 100
  • eigo = 100
メソッド String getName() 生徒の名前(name)を戻り値として返す
void printGoukei() 国語、数学、英語の合計点を計算し、「合計は、xxx点です。」と画面に表示する

Seiseki1.java
/**
 * 処理概要:生徒の国語、数学、英語の成績を扱うクラス
 */
public class Seiseki1 {

	// フィールド定義
	String name; // 生徒の名前
	int kokugo; // 国語の点数
	int sugaku; // 数学の点数
	int eigo; // 英語の点数

	// コンストラクタ定義
	Seiseki1() {
		// 各フィールドを初期化
		name = "山田";
		kokugo = 100;
		sugaku = 100;
		eigo = 100;
	}

	// フィールドnameの値を戻すメソッド
	String getName() {
		return name;
	}

	// 合計点を出力するメソッド
	void printGoukei() {
		int sum = kokugo + sugaku + eigo;
		System.out.println("合計は、" + sum + "点です。");
	}
}

利用されるクラスの復習問題です。

フィールド、メソッド、コンストラクタと各構文の形式をしっかり押さえましょう。
フィールドは、変数ですが、定義する場所だけ注意が必要です。

フィールドは、クラスの「{} 中括弧」の中に記述します。
メソッドやコンストラクタ、その他の中括弧の中に記述すると「ローカル変数」となり、フィールドとして認識されません。

コンストラクタは、インスタンス化をするときに呼ばれる特殊なメソッドです。
戻り値はありませんので、戻り値のデータ型やreturn文は記述できません。クラスと同じ名前のメソッド名で定義します。

メソッドは、メソッド名の前に戻り値のデータ型を記述します。
合計点を出力するメソッドは戻り値がありませんので、戻り値のデータ型の代わりに「void」と記述します。

戻り値があるメソッドには、return文を忘れないようにしましょう。

10.2.問題2

問題1で作成した利用されるクラスを利用するクラスClassMondai1を作成しましょう。
Seiseki1クラスをインスタンス化し、getNameメソッドを利用して、「山田さんの成績:」と画面に表示してください。
そのあと、printGoukeiメソッドを利用して、「合計は、xxx点です。」も画面に表示してください。

ClassMondai1.java
/**
 * 処理概要:Seiseki1クラスを利用し、取得した合計点を出力
 */
public class ClassMondai1 {
	public static void main(String[] args) {
		// Seiseki1クラスのインスタンス化
		Seiseki1 sk1 = new Seiseki1();

		// 名前の取得
		String str = sk1.getName();

		// 取得した名前の出力
		System.out.println(str + "さんの成績:");

		// 合計点の出力
		sk1.printGoukei();
	}
}

他のクラスの機能を利用する場合、最初にインスタンス化を行い、オブジェクトを生成します。
インスタンス化は、「new 利用したいクラス名()」です。
生成したオブジェクトを、そのあとの処理で扱いやすいように、Seiseki1クラスの型の変数sk1に代入しています。

インスタンス化をすると、Seiseki1クラスのコンストラクタが呼ばれ、各フィールドが初期化されます。
フィールドnameには「山田」、各点数フィールドには「100」が代入されます。

そのあとに、getNameメソッドを「sk1.getName()」で呼び出し、フィールドnameの値を戻り値として取得して出力しています。
あとは、printGoukeiメソッドを「sk1.printGoukei()」で呼び出し、合計点を算定し出力する処理を行ってもらっています。

11.練習問題3

コンストラクタに関する練習問題です。

11.1.問題1

まずは、利用されるクラスの定義についての問題です。
以下の指定通りにSeiseki2クラスを記述しましょう。

表 2. Seiseki2クラス
クラス Seiseki2
フィールド String name 生徒の名前
int kokugo 国語の点数
int sugaku 数学の点数
int eigo 英語の点数
コンストラクタ Seiseki2(String tName, int tKokugo, int tSugaku, int tEigo) 各フィールドを、引数の値で初期化する
メソッド String getName() 生徒の名前(name)を戻り値として返す
int getGoukei() 国語、数学、英語の点数の合計を戻り値として返す
double getAverage() 国語、数学、英語の点数の平均を戻り値として返す

※この問題の解答は掲載しておりません。Tech Fun ITスクールのJava研修では、講師が丁寧に解説しています。

11.2.問題2

問題1で作成した利用されるクラスを利用するクラスClassMondai2を作成しましょう。
Seiseki2クラスをインスタンス化してください。
インスタンス化時に自分の名前と国語、数学、英語の点数を引き渡して、フィールドに各値を設定します。
getNameメソッドを利用して、「XXさんの成績:」と画面に表示してください。
そのあと、getGoukeiメソッドを利用して合計点を取得し、「合計は、xxx点です。」も画面に表示してください。
最後に、getAverageメソッドを利用して平均点を取得し、「平均は、xxx点です。」と画面に表示してください。

※この問題の解答は掲載しておりません。Tech Fun ITスクールのJava研修では、講師が丁寧に解説しています。

12.static修飾子

ここでは、メインメソッドを定義する時にも記述していた、static修飾子について説明します。

フィールドやメソッドにstatic修飾子をつけた場合、定義したときに実体を生成するため、
クラスをインスタンス化せずにアクセスすることができます。(インスタンス化してもアクセスすることは可能です)。
そしてこれらを「クラス変数」、「クラスメソッド」と呼びます。
なお、インスタンス化をしてアクセスする変数やメソッドは、「インスタンス変数」「インスタンスメソッド」と呼びますので、同時に用語を覚えておきましょう。

以下がクラス変数とクラスメソッドの定義の書式です。

// クラス変数
static データ型 フィールド名;
// クラスメソッド
static 戻り値の型 メソッド名(引数リスト) {・・・・・・・・・・・}

また、クラス変数とクラスメソッドへのアクセスは、下記のようにクラス名にピリオドを付けてアクセスします。

クラス名.フィールド名
クラス名.メソッド名(引数リスト)

12.1.クラス変数

クラス変数は、クラスが複数インスタンス化されても、常にクラス内の変数が使用されるので、一つしか存在しません。
そのため、クラス全部に共通の変数となり、クラス変数の値は全体で共有されます。
これによりクラス変数は、インスタンスを生成してもインスタンス毎に変数が作られずに、同じ値が共有されます。

以下がクラス変数のサンプルソースです。
今回はクラス変数の動きを確認するために、インスタンスを生成して値を設定した後に、
インスタンス化した各変数を使ったアクセスと、インスタンス化せずにクラス名でのアクセスの両方を
行っています。

StaticStudy1.java
public class StaticStudy1 {
	// クラス変数
	static int classField;
}
RiyoStatic1.java
public class RiyoStatic1 {
	public static void main(String[] args) {
		// StaticStudy1を2つインスタンス化します
		StaticStudy1 ss1Sample1 = new StaticStudy1();
		StaticStudy1 ss1Sample2 = new StaticStudy1();

		// インスタンス ss1Sample1 の変数 classField に 10 を代入しても
		ss1Sample1.classField = 10;

		// インスタンス ss1Sample2 の変数 classField に 5 を代入すると
		ss1Sample2.classField = 5;

		// インスタンス ss1Sample1 の変数 classField も 5 になります
		System.out.println(ss1Sample1.classField);
		System.out.println(ss1Sample2.classField);

		// インスタンス化せずにアクセスして出力しても結果は 5 になります。
		System.out.println(StaticStudy1.classField);
	}
}

実行結果は、以下のとおりとなります。

5
5
5

12.2.クラスメソッド

クラスメソッドもクラス変数同様、常に一つしか存在せず全体で共有されます。

以下が、クラスメソッドのサンプルソースです。

StaticStudy2.java
public class StaticStudy2 {
	// クラスメソッド
	static String getClassMethod() {
		return "クラスメソッドです" ;
	}
}
RiyoStatic2.java
public class RiyoStatic2 {
	public static void main(String[] args) {
		System.out.println(StaticStudy2.getClassMethod());
	}
}

実行結果は、以下のとおりとなります。

クラスメソッドです
12.2.1.mainメソッド

今までプログラムで扱ってきたmainメソッドを使ってきましたが、このメソッドはstatic修飾子がついていることから分かるように、クラスメソッドとなります。

public class MyMain1 {
	public static void main(String[] args) {
		// main メソッドはクラスメソッド
	}
}

そのため、mainメソッドを持つクラスを定義した時に実体を生成するため、Java仮想マシンはmainメソッドをインスタンス化せずに呼び出すことができます。

12.2.2.static修飾子の注意点

ここまでの説明を読んだ方の中には、すべてのメソッドにstaticを付けてしまえば、そのメソッドを使用したい場合、インスタンス化をする必要がなく便利なのではないか、と思った人もいるのではないでしょうか。

この後学習する「インヘリタンス」の章と「ポリモフィズム」の章では、継承という考え方が登場します。
継承はオブジェクト指向で非常に重要な考え方であり、Java言語は基本、この考え方をもとにコーディングを行っていきます。

詳細は「インヘリタンス」の章と「ポリモフィズム」の章で説明をしますが、クラスの継承によりプログラムの拡張性が大きく広がります。
ただし、クラスメソッドは定義されているクラスに属するメソッド(静的メソッドとも呼ばれます)となるため、再定義して拡張することができません。

また、Webアプリケーションなどでは、複数の人が同時にアプリケーションにアクセスすることを想定してプログラム構成を考える必要があります。
この時、深く考えずにstatic修飾子を使用してしまうと、変数やメソッドが複数人で共有されることになり、意図せぬ結果を招いてしまうことにもなりかねません。

そのため、static修飾子を使う場合には、挙動をしっかりと認識したうえで利用するようにしましょう。

Information

クラス変数、およびクラスメソッドは、インスタンス化せずに使用できるため、
クラスメソッド内でインスタンス化が必要となるインスタンス変数やインスタンスメソッドを直接記述すると、構文エラーになります。

以下がサンプルソースです。

MyStaticError.java
public class MyStaticError {
	int instanceHensu = 5; // インスタンス変数
	static int classHensu = 10; // クラス変数

	public static void main(String[] args) {
		// 下記はエラーとならず、問題なく使用できます。
		System.out.println(classHensu);
		classMethod();
		// 下記は、構文エラーになります。
		System.out.println(instanceHensu);
		instanceMethod();
	}
	// インスタンスメソッド
	void instanceMethod() {
		System.out.println("インスタンスメソッドです");
	}
	// クラスメソッド
	static void classMethod() {
		System.out.println("クラスメソッドです");
	}
}

インスタンス変数とインスタンスメソッドを呼び出したい場合は、クラスをインスタンス化して呼び出せば、利用は可能です。

System.out.println(instanceHensu);
instanceMethod();
↓
MyStaticError myStaticError = new MyStaticError();
System.out.println(myStaticError.instanceHensu);
myStaticError.instanceMethod();

少し挙動が分かりづらいかもしれませんが、色々とソースを変更してみて動作を確認し、理解してみると良いでしょう。

13.練習問題4

引数と戻り値の練習問題です。
練習問題2で作成した利用されるクラスSeiseki1クラスを元に新しいクラスを作成しましょう。

13.1.問題1

まずは、利用されるクラスの定義についての問題です。
以下の指定通りにSeiseki3クラスを記述しましょう。

表 3. Seiseki3クラス
クラス Seiseki3
フィールド String name 生徒の名前
メソッド void setName(String tName) 生徒の名前(name)に引数tNameの値を代入する
String getName() 生徒の名前(name)を戻り値として返す
int getGoukei(int tKokugo, int tSugaku, int tEigo) 引数に入力された国語、数学、英語の合計点を戻り値として返す

Seiseki3.java
/**
 * 処理概要:生徒の国語、数学、英語の成績を扱うクラス
 */
public class Seiseki3 {
	// フィールド定義
	String name; // 生徒の名前

	// フィールドnameに引数の値を代入するメソッド
	void setName(String tName) {
		name = tName;
	}

	// フィールドnameの値を戻すメソッド
	String getName() {
		return name;
	}

	// 合計点を戻すメソッド
	int getGoukei(int tKokugo, int tSugaku, int tEigo) {
		int sum = tKokugo + tSugaku + tEigo;
		return sum;
	}
}

コンストラクタの記述がないクラスの定義の例です。
コンストラクタがない場合、デフォルトコンストラクタ(引数を持たないコンストラクタ)がコンパイル時に自動的に定義されます。
このクラスをインスタンス化するときには、 そのコンストラクタが暗黙的に使用されて、インスタンス化されます。

フィールドの定義については、練習問題1と同様です。

メソッドの定義については、setNameメソッド、getGoukeiメソッドに引数を設けます。
引き渡される値を引き受けるために、メソッド名の後の丸括弧内に変数を記述します。

13.2.問題2

問題1で作成した利用されるクラスを利用するクラスClassMondai3を作成しましょう。
Seiseki3クラスをインスタンス化し、setNameメソッドを利用して、自分の名前をフィールドnameに設定してください。
そのあと、getNameメソッドを利用して、「XXさんの成績:」と画面に表示してください。
そのあと、getGoukeiメソッドを利用して、引数に国語、数学、英語の任意の点数を引き渡し、合計点を取得して「合計は、xxx点です。」と画面に表示してください。

ClassMondai3.java
/**
 * 処理概要:Seiseki3クラスを利用し、取得した合計点を出力
 */
public class ClassMondai3 {
	public static void main(String[] args) {

		// Seiseki3クラスのインスタンス化
		Seiseki3 sk3 = new Seiseki3();

		// 自分の名前をセット
		sk3.setName("XXXX");

		// 名前の取得
		String str = sk3.getName();

		// 取得した名前の出力
		System.out.println(str + "さんの成績:");

		// 国語、数学、英語の点数を引き渡し、合計点を取得
		int sum = sk3.getGoukei(40, 50, 60);

		// 合計点の出力
		System.out.println("合計は、" + sum + "点です。");
	}
}

引数が必要なメソッドを呼び出すときは、メソッド名の後の丸括弧の中に引き渡す値をセットします。
引数は、引き渡す値の数やデータ型が、呼ばれる側のメソッドの引数の変数と一致していれば、値が引き渡されます。
数やデータ型が異なると、エラーとなりますので注意しましょう。

13.3.問題3

問題1で作成した利用されるクラスのgetNameメソッドとgetGoukeiメソッドをクラスメソッドに変更してください。
そのあと、問題2で作成したClassMondai3をクラスメソッドの呼び出し方に処理を変更し、同じ出力結果が表示されるようにしてください。

Seiseki3.java
/**
 * 処理概要:生徒の国語、数学、英語の成績を扱うクラス
 */
public class Seiseki3 {
	// フィールド定義
	static String name; // 生徒の名前

	// フィールドnameに引数の値を代入するメソッド
	void setName(String tName) {
		name = tName;
	}

	// フィールドnameの値を戻すメソッド
	static String getName() {
		return name;
	}

	// 合計点を戻すメソッド
	static int getGoukei(int tKokugo, int tSugaku, int tEigo) {
		int sum = tKokugo + tSugaku + tEigo;
		return sum;
	}
}

ここでのポイントは、クラスメソッドでフィールドの値を使用する場合、そのフィールドにもstaticを付加します。
これは、インスタンス化しないでフィールドを使う場合、そのフィールドにも最初から実体をもたせる必要があるからです。
そのため、staticを付加していないフィールドをクラスメソッドで使用すると、エラーになりますので、注意しましょう。

あとは、getNameメソッドとgetGoukeiメソッドにそれぞれstaticを付加して、クラスメソッドにします。
クラスメソッドは最初から実体があるメソッドであるため、インスタンス化をしなくても呼び出すことが可能になります。

ClassMondai3.java
/**
 * 処理概要:Seiseki3クラスを利用し、取得した合計点を出力
 */
public class ClassMondai3 {
	public static void main(String[] args) {

		// Seiseki3クラスのインスタンス化
		Seiseki3 sk3 = new Seiseki3();

		// 自分の名前をセット
		sk3.setName("XXXX");

		// 名前の取得
		String str = Seiseki3.getName();

		// 取得した名前の出力
		System.out.println(str + "さんの成績:");

		// 国語、数学、英語の点数を引き渡し、合計点を取得
		int sum = Seiseki3.getGoukei(40, 50, 60);

		// 合計点の出力
		System.out.println("合計は、" + sum + "点です。");
	}
}

staticがついたクラスメソッドを呼び出すときには、インスタンス化してから呼び出す必要がありません。
「クラス名.メソッド名(引数リスト)」で呼び出します。
getNameメソッドとgetGoukeiメソッドをクラスメソッドに変更しましたので、「Seiseki3.getName()」、「Seiseki3.getGoukei(40, 50, 60)」で呼び出します。

14.本章のまとめ

  • クラスはフィールドとメソッドを持つことができる。
  • メソッドに戻り値がある場合は「return文」を使用して戻り値を返却する。
  • メソッドに戻り値がない場合は、戻り値の型は「void」となり、return文も使用しない。
  • クラスはインスタンス化してから使用し、「参照変数名.メソッド名()」や「参照変数名.フィールド名」のような形でメソッドやフィールドを使用する。
  • メソッドの実行時に、利用されるクラスへ引数を渡すには、メソッド名の後ろにある「()括弧」の中にデータ(値)を記述する。
  • 「コンストラクタ」は、フィールドを初期化する特別なメソッドなので、クラス名と同じ名前で定義する。
  • 「static修飾子」がついたフィールドやメソッドは、インスタンス化せずに使用可能(ただし、定義・使用時には注意が必要)。

以降の章では、利用されるクラスを扱う機会も多くなってきます。
扱い方に不安がある場合は、教材をもう一度読み直すなどして復習しておきましょう。

クラスについての説明は、以上です。

執筆・編集

Tech Fun Magazine編集部
Tech Funの現役のITエンジニアが、システム開発の基礎知識や実践的なノウハウを執筆・編集しています。
Tech Fun ITスクールの研修講師として活躍するメンバーもおり、プログラミング初心者がつまづきやすいポイントを丁寧に解説しています。

ARTICLE
記事一覧

Java基礎

Java12からJava17までに導入された機能の紹介

システム開発の基本

プログラミングとテストの要点

データベース環境構築

データベース環境構築(Windows版) テストデータ作成

データベース環境構築

データベース環境構築(Windows版) MariaDBの設定

データベース環境構築

データベース環境構築(Mac版) テストデータ作成

データベース環境構築

データベース環境構築(Mac版) MariaDBの設定

Java基礎

はじめてのJava

Java基礎

Javaのデバッグ方法

Java基礎

ポリモフィズム

記事一覧を見る