インスタンスメンバとstaticメンバ
これまで見てきたフィールドやメソッドは、static修飾子がついていないメンバです。
これらはインスタンスフィールドおよびインスタンスメソッドとよばれ、newキーワードを使用してクラスからインスタンス化されたインスタンス(オブジェクト)ごとに生成されます。
インスタンスはメモリ上のヒープ領域という場所に格納されます。
一方、フィールドやメソッドに、staticという修飾子を付けるとstatic(静的)フィールド、staticメソッドになります。
これらをstatic(静的)メンバと呼びます。
staticメンバはメモリ上のstatic領域という場所に格納されます。
staticメンバはクラスが呼び出される時に呼び出されるメンバで、クラスに1つだけ生成されます。
インスタンスメンバを利用するには、インスタンスを作成し、そのインスタンスから呼び出していました。
所属するインスタンス名(オブジェクト名).インスタンスメンバ
(例) MyClass taro = new MyClass(); taro.name; taro.age; taro.height;
staticメンバを利用するには、インスタンスは作成せずに、クラス名で呼び出します。
所属するクラス名.staticメンバ
(例) MyClass.total;
ポイント!staticフィールドの使用例
staticメンバはクラスから作成されたすべてのインスタンス(オブジェクト)からアクセスすることが可能です。
すなわちすべてのインスタンスから共通で扱えるメンバとなるので、どのインスタンスからも1つの値を持ちあうような場合に使用すると便利です。
例えば、クラスのインスタンスの数を数えたいといった場合、totalといったstaticフィールドを作成しておき、インスタンスが生成されるたび ++totalとすることで、インスタンスの数をカウントすることができます。
【staticフィールドの呼び出し】
public class MyClass { String name; static int total; public static void main(String[] args) { MyClass taro = new MyClass(); taro.name = "太郎"; MyClass.total = ++total; System.out.println(taro.name + "インスタンスが作成されました。totalの値:"+ total); MyClass jiro = new MyClass(); jiro.name = "次郎"; MyClass.total = ++total; System.out.println(jiro.name + "インスタンスが作成されました。totalの値:"+ total); MyClass saburo = new MyClass(); saburo.name = "三郎"; //MyClass.total = ++total; ++total; System.out.println(saburo.name + "インスタンスが作成されました。totalの値:"+ total); } }
実行結果
太郎インスタンスが作成されました。totalの値:1 次郎インスタンスが作成されました。totalの値:2 三郎インスタンスが作成されました。totalの値:3
MyClassクラスには、インスタンスフィールドであるnameとstaticフィールドtotalが定義されています。
taro、jiro、saburoと3つのインスタンスを作成し、それぞれのインスタンスから++totalと記述し、staticフィールドに1ずつ加算をしています。
staticフィールドはクラスに1つだけ存在する、すべてのインスタンスから共通でアクセスできるフィールドなのであることがわかります。
staticメンバにアクセスする場合、「クラス名.staticメンバ名」と記述することが基本ですが、19行目のように同じクラス内であれば、クラス名を省略することができます。
【staticメソッドの呼び出し】
public class MyData { private static int total = 0; public static int getTotal(){ return ++total; } }
public class MyClass2 { String name; public static void main(String[] args) { MyClass2 taro = new MyClass2(); taro.name = "太郎"; System.out.println(taro.name + "インスタンスが作成されました。totalの値:"+ MyData.getTotal()); MyClass2 jiro = new MyClass2(); jiro.name = "次郎"; System.out.println(jiro.name + "インスタンスが作成されました。totalの値:"+ MyData.getTotal()); MyClass2 saburo = new MyClass2(); saburo.name = "三郎"; System.out.println(saburo.name + "インスタンスが作成されました。totalの値:"+ MyData.getTotal()); } }
実行結果
太郎インスタンスが作成されました。totalの値:1 次郎インスタンスが作成されました。totalの値:2 三郎インスタンスが作成されました。totalの値:3
MyDataクラスにstatic フィールドtotalとそのゲッターメソッドgetTotal()をstaticとして定義しています。
このゲッターメソッドの中で++totalとし、実行されるたびにtotalに1加算されるようにしておきます。
MyClass2クラスからtaro、jiro、saburoと3つのインスタンスを作成し、それぞれのインスタンスからstaticメソッドgetTotal()を呼び出しています。
staticメソッドはクラスに1つだけ存在する、すべてのインスタンスから共通でアクセスできるメソッドです。
MyData.getTotal()と記述し、クラス名.staticメソッド名でアクセスしています。
staticメンバからインスタンスメンバへのアクセス
クラスに定義されたフィールドやメソッドはmain()メソッドからアクセスをしますが、staticメソッドからstaticでないフィールド(インスタンスフィールド)に直接アクセスすることはできません。
これまで見てきたとおりインスタンスフィールドにアクセスするには、インスタンスを作成してからアクセスをする必要があります。
【staticメンバからインスタンスメンバへのアクセス】
public class MyData2 { private int total = 0; public static void main(String[] args) { System.out.println(++total); } }
staticメンバはクラスが読み込まれた時に、メモリ上に生成されます。
一方、インスタンスメンバはクラスがnewされてインスタンス化されたときにはじめてメモリ上に生成されます。
staticメンバからインスタンスメンバへアクセスできないのは、staticメンバが生成された時点で、インスタンス化が行われておらず、インスタンスメンバが存在していない可能性があるからです。
staticイニシャライザ
クラスには、staticフィールド、staticメソッドに加え、staticイニシャライザと呼ぶブロックを定義することができます。
staticイニシャライザはクラスが読み込まれた時に実行されるブロックです。
クラスをインスタンス化する前やmain()メソッドを呼び出す前に実行したい処理があった場合に利用します。
構文は次の通りです。
static{ クラスが読み込まれるタイミングで実行したい処理 }
【staticイニシャライザ】
StaticMyDataクラス
public class StaticMyData { static int data = 10; static{ System.out.println("dataの初期値は:" + data); data = 100; System.out.println("staticイニシャライザが呼ばれました。dataの値は:" + data); } StaticMyData(){ data = 200; System.out.println("コンストラクタが呼ばれました。dataの値は:" + data); } }
StaticMainクラス
public class StaticMain { public static void main(String[] args) { StaticMyData obj = new StaticMyData(); } }
実行結果
dataの初期値は:10 staticイニシャライザが呼ばれました。dataの値は:100 コンストラクタが呼ばれました。dataの値は:200
StaticMyDataクラスにstaticイニシャライザを定義し、最初にフィールドdataの初期値を表示し、その後dataに100を代入し、表示するようにしておきます。
またコンストラクタを定義し、フィールドdataに200を代入し、表示するようにしておきます。
StaticMainクラスのmain()メソッドでStaticMyDataクラスをインスタンス化していますが、コンストラクタが呼ばれる前に、staticイニシャライザが実行されていることがわかります。
まとめ
静的メンバ
- staticメンバはインスタンスではなく、クラス固有となります。
- staticメンバは、クラスのインスタンスから共有できます。
- staticメンバにアクセスするには、「クラス名.staticメンバ」と記述します。
- staticメンバから、staticでないメンバ(インスタンスメンバ)に直接アクセスできません。アクセスする場合はインスタンスを作成します。
- staticイニシャライザは、クラスが読み込まれたタイミングで実行されます。
独学で挫折しそうになったら、オンラインプログラミングスクール