【Java】staticについて
はじめに
Javaにおける”static”の使い方はいくつかありますが、本記事ではその中でも『静的メンバとして使われる”static”』について解説していきます。
staticとは
そのまま英語に直訳すると、”静止した””動かない””固定された”という意味になります。この記事を最後まで読んでいただければ、この直訳の意味がなんとなく分かるようになるかと思います。
Javaのオブジェクト指向によるクラスの作成をを学習していく中で、”静的メンバ”というワードを耳にしたことがあるでしょうか。
”静的メンバ”とは、”static”という修飾詞がついたメンバ変数やメソッドのことを指します。
static変数
一言でいうと、static変数とはインスタンスとして使うものではなく、あくまでクラス定義で使う変数のことです。あるクラスをインスタンス化すれば、そのクラスファイルをもとにインスタンスが生成されますが、その中にstatic修飾詞がついた変数フィールドがある場合はそのフィールドがインスタンスとして動く事はなく、もとになるクラスファイル上で参照される事になります。つまり、いくら複数のインスタンスをつくろうと、static変数は共通でクラスファイル上の1つ、ということになります。
実際のコードで確認していきましょう。
まず、下記のようなHumanクラスがあったとします。
class Human {
//フィールド↓
static int count;
int number;
//コンストラクタ↓
Human(){
this.count++;
}
}
ここで、mainメソッドのある下のクラスからHumanクラスのstatic変数(count)のみ値を代入し、表示するコードを実行すれば
class Main {
public static void main(String[] args) {
Human.count = 1;
System.out.println(Human.count);
}
}
実行結果は以下のようになります。
=実行結果=
1
このように、static変数はインスタンス化しなくても利用することができます。
では、続いてstaticの付いていない、非static変数も同様に値の代入をしようと思います。
class Main {
public static void main(String[] args) {
Human.number = 1;
System.out.println(Human.number);
}
}
しかし、結果は下のようにコンパイルエラーになります。
=実行結果=
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
非 static フィールド Human.number を static 参照できません
非 static フィールド Human.number を static 参照できません
2行同じエラーが出ているのは、3行目と4行目両方とも非static変数を参照しようとしたからです。
このように、非static変数はインスタンス化をしないと扱うことはできません。
では、Humanクラスをインスタンス化した後に非static変数を変更してみましょう。ついでにコンストラクタによるcountフィールドの値の変化にも注目してみてください。
class Main {
public static void main(String[] args) {
//-----------インスタンス化
Human father = new Human();
Human mother = new Human();
//-----------number値代入後、number値とcount値の表示
father.number =1;
System.out.println("father:" + father.number + ", count:" + father.count);
mother.number =2;
System.out.println("mother:" + mother.number + ", count:" + mother.count);
}
}
この実行結果は、下のようになります。
=実行結果=
father:1, count:2
mother:2, count:2
上では2つのインスタンスを生成し、無事両方とも非static変数に値を代入できています。また、インスタンス化直後のコンストラクタによりcountフィールドに1を追加しています。countフィールドを表示した場合、もし仮にこれが非static変数であれば、その値は1と表示されるはずですが、static変数のため、値が2と表示されています。
このように、static変数はインスタンス毎に持つものではなく、共通で1つのデータとして利用できるものだという事がわかります。
このため、static変数は複数のインスタンス間で値を共有したいケースに使うことができます。
staticメソッド
static修飾詞のついたメソッドは、実はJava言語を学習しはじめる頃から何気なく使っているはずです。”public static void main(String[] args) {}”、これがまさにstaticメソッドです。staticメソッドもstatic変数と同様、インスタンス化せずクラスファイル上でのみ定義されるメソッドです。オブジェクト指向のクラス作成を学習していると、mainメソッド以外には基本的にstaticは付けない、と習うことでしょう。なぜならオブジェクト指向に従えば、mainメソッドのあるMainクラスはインスタンス化せずに他のクラスをインスタンス化してメソッドを実行する、いわゆる司令塔のような役割になり、Mainクラス自身はインスタンス化することがないからです。
では試しに、先程使ったMainクラスのmainメソッドから”static”だけ抜き取って実行してみましょう。
class Main {
public void main(String[] args) {・・・略・・・}}
すると、結果はこのようになります。
=実行結果=
エラー: メイン・メソッドがクラスchapter01.Mainのstaticではありません。次のようにメイン・メソッドを定義してください。
public static void main(String[] args)
“static”を取り除いたことで、このMainクラスもインスタンス化をしないとメソッドの使用ができなくなってしまう訳です。このようなstaticメソッドの使いどころとしては、インスタンスを生成せずに楽にメソッドを呼び出したい場合や、Java APIの中で、外部よりインスタンス化を禁止しているクラスに用意された、”インスタンス生成を担当する静的(static)メソッド”を呼び出す場合などが挙げられます。
ここまでstatic変数、staticメソッドの説明をしてきましたが、最後に、static絡みのアクセスについて簡単に説明します。
今までの説明の通り、static修飾詞の付いたものはインスタンス化せずに利用することができます。ゆえにstaticメソッドからインスタンス前の非staticメソッドへアクセスさせるようなコードを書くとエラーになります。staticメソッドからstatic変数へアクセスするコードはエラーになりません。
おわりに
いかがでしたでしょうか。staticは、その使用意図をはっきり持ち合わせた上で活用しないと、開発の規模が大きいものほどコードの読解が複雑になったり、意図せず外部からデータを書き換えられたり、不具合を生むリスクもあります。今回は初歩的な部分ではありましたが、staticについて少しでも参考になれば幸いです。最後まで読んでいただきありがとうございました。