初心者入門レベルの【Javaの勉強】クラス変数・クラスメソッドとコンストラクタ
2020/04/02
Javaには「オブジェクト指向」の概念が取り入れられていますが、完全に「オブジェクト指向」に従った仕様にはなっていません。
その違いの代表といえるのが、「クラス変数」と「クラスメソッド」になるでしょう。
厳密な「オブジェクト指向」では「クラス」は「インスタンス化」して始めて使用することができますが、Javaの「クラス変数」と「クラスメソッド」は「インスタンス化」することなくそのまま使用できます。
今回は、その「クラス変数」「クラスメソッド」についてと、さらに「コンストラクタ」について勉強します。
「クラス変数」と「クラスメソッド」
前述のとおり「オブジェクト指向」では「クラス」は「インスタンス化」すること無しに使用することはできませんが、現実問題としてそれでは効率が悪いことがあります。
例えば一度しか「インスタンス化」しない「クラス」、つまり「オブジェクト」が1つしか必要ない「クラス」の場合は、わざわざ「インスタンス化」するのは処理速度の面からもメモリの使用量の面からも非効率と言えます。
そこでJavaでは理論よりも効率を優先する方法として、「クラス」内の変数やメソッドを直接利用できる仕組みを用意しました。
この「インスタンス化」しないで直接利用できる変数やメソッドのことをそれぞれ、「クラス変数」「クラスメソッド」と呼びます。
Javaで数値計算のために用意された“Math”というクラスなども、円周率の値を「クラス変数」として持ち、平方根などの演算を「クラスメソッド」として持っています。
円周率は常に同じ値を保持するもので、平方根の演算も一度結果を得られれば後は必要ないので、それぞれその度ごとに「インスタンス化」する必要がないからです。
ここで似たようなサンプルとして、円の面積を求めるプログラムを作ってみましょう。
まずは以下のように、円周率を計算する機能を持つ「クラス」を定義します。
class CircleClass01 {
static final double RATIO = 3.14;
static double getArea(double radius) {
return radius * radius * RATIO;
}
}
「クラス変数」「クラスメソッド」を定義するには、宣言時にアクセス修飾子の後ろに“static”と付けますが、アクセス修飾子が無い場合はこのように“static”が先頭になります。
続いて、この「クラス」を使って円の面積を求めるプログラムを以下のように作ります。
public class TestCircle01 {
public static void main(String[] args) {
double myRadius = 5.0;
double myArea = CircleClass01.getArea(myRadius);
System.out.print("半径" + myRadius + "の円の面積は" + myArea + "です。");
System.out.println("(円周率を" + CircleClass01.RATIO + "とする)");
}
}
これでも分かるように、修飾子“static”をつけて定義した「クラス変数」「クラスメソッド」は、「インスタンス化」しないでそのまま利用することができます。
また、上記の2つのプログラムを次のように一つの「クラス」の中にまとめて、同じ「クラス」内で「クラス変数」「クラスメソッド」を使うようにした場合、「クラス名」を省略することができます。
class CircleClass02 {
static final double RATIO = 3.14;
static double getArea(double radius) {
return radius * radius * RATIO;
}
public static void main(String[] args) {
double myRadius = 5.0;
double myArea = getArea(myRadius);
System.out.print("半径" + myRadius + "の円の面積は" + myArea + "です。");
System.out.println("(円周率を" + RATIO + "とする)");
}
}
「コンストラクタ」
続いて、「コンストラクタ」について勉強しましょう。
「コンストラクタ」というのは「クラス」から「インスタンス」を生成する際に必ず呼ばれる「メソッド」で、「メソッド」生成の際に必ず実行したい処理があるときに利用される機能です。
例として、まずは以下のプログラムを作ってみましょう。
class CountClass07 {
private int count;
public void setCount(int i) {
count = i;
}
public int getCount() {
return count;
}
}
public class TestCount05 {
public static void main(String[] args) {
CountClass07 cnt = new CountClass07();
cnt.setCount(10);
System.out.println("現在のカウントは" + cnt.getCount() + "です。");
}
}
このプログラムでは、“CountClass07”の「インスタンス」を生成した後に、改めて「アクセサ」を使って“count”の値をセットしています。
“CountClass07”は「インスタンス」が生成されるたびに必ず“count”の値がセットされるべき「クラス」になっていますが、そのつど毎回「アクセサ」で値をセットするのは面倒と言えるでしょう。
そこでこういった場合に使われるのが「コンストラクタ」で、以下のようにプログラムを変更することで実現できます。
class CountClass08 {
private int count;
CountClass08(int count) {
this.count = count;
}
public int getCount() {
return count;
}
}
public class TestCount06 {
public static void main(String[] args) {
CountClass08 cnt = new CountClass08(10);
System.out.println("現在のカウントは" + cnt.getCount() + "です。");
}
}
「コンストラクタ」は、「クラス名」と同じ名前の「メソッド」で、引数がある場合も無い場合もあります。
ここで呼び出し側のプログラムで“new”演算子で「インスタンス」を生成している部分で、引数として変数“count”にセットする値を渡しているところに注目してください。
こうすることで、「インスタンス」の生成後に改めて「アクセサ」を使う必要が無くなるわけです。
ところで、このプログラムで“this”という記述が初めて出てきましたが、これは自分自身の参照値を持つ変数を表しています。
つまりこの場合は、“this.count”は「コンストラクタ」の外で宣言された変数で、“count”は「コンストラクタ」の引数として宣言された変数を指しているので注意が必要です。
この“this”を使って、他の「インスタンス」の「メソッド」に自分の参照値を渡すときにも利用できます。
さて、今回初めて利用した「コンストラクタ」ですが、これが記述されていないプログラムでも「コンストラクタ」が実行されていないわけではありません。
例えば、以下のような「クラス」があった場合。
class CountClass {
private int count = 10;
}
これをコンパイルすると、Javaの処理系が自動的にデフォルトの「コンストラクタ」を作成して、以下のような「クラス」と同じものになります。
class CountClass {
private int count = 10;
CountClass() {}
}
この場合、デフォルトの「コンストラクタ」の中身は空っぽですが、実行されると「スーパークラス」の「コンストラクタ」が呼び出されるという機能があります(「スーパークラス」については改めて勉強します)。
ちなみに「コンストラクタ」は、その型や引数の数を変えることによって、1つの「クラス」の中に複数定義することもできます。
例として、以下のプログラムを作ってみましょう。
class CountClass09 {
private int count;
CountClass09() {
this.count = 1;
}
CountClass09(int count) {
this.count = count;
}
public int getCount() {
return count;
}
}
public class TestCount07 {
public static void main(String[] args) {
CountClass09 cnt1 = new CountClass09();
System.out.println("現在のカウントは" + cnt1.getCount() + "です。");
CountClass09 cnt2 = new CountClass09(10);
System.out.println("現在のカウントは" + cnt2.getCount() + "です。");
}
}
最初の「インスタンス」では引数を渡していないので引数をとらない「コンストラクタ」が呼び出され、次の「インスタンス」では引数を渡しているので引数をとる「コンストラクタ」が呼び出されます。
実際にこれを実行してみると、以下のような結果が確認できます。
>java TestCount07
現在のカウントは1です。
現在のカウントは10です。
>
まとめ
今回は、「クラス変数」と「クラスメソッド」、そして「コンストラクタ」について勉強しました。
どれも効率の良いプログラムを作るために必要な機能なので、十分理解して利用できるようにしておきたいですね。
それでは、今回はここまでです。
《 【Javaの勉強】一覧 》