今回はstaticについてまとめていきます。
Java Bronze試験でもよく出るので覚えるために書き殴ってみます。
staticとは
インスタンスと比較されることが多いです。インスタンスとstaticの違いについて
実行する際の領域の確保に違いがある。
と覚えていいと思います。
基本的にメソッドとフィールドにstaticを付けることができます。
staticを付けるとクラスオブジェクト、静的メンバ(クラス変数・クラスメソッド)となります。
staticがついているものは領域が共有化。つまり、staticという名前の領域にまとめて値がぶち込まれるというイメージになると思います。(おそらく厳密には違いますが覚えやすいのでこういう風にイメージしています。)
なので例えば、変数strにstaticを付ければ、mainメソッドで別々の名前でオブジェクトを作ったとしても(str1とstr2)変数strとしてstatic領域に保存されているのでstr1に”あ”と代入した場合str2も中身が”あ”と自動的に代入される。ということですね。リンクしてるみたいなものでしょうか。
こうなると以前やったインスタンスと少し違うのかな?と感じますよね。
インスタンスとの違い
インスタンスの記事でも説明した通り、インスタンスは呼び出したいクラスのコンストラクタを呼び出してオブジェクトに入れてオブジェクトを作り、使えるようにする。というものでしたよね。
インスタンスで作ったモノをインスタンスオブジェクト(インスタンス変数/インスタンスメソッド)と呼びます。インスタンスメンバは複数オブジェクトを作成しても共有化されず作ったオブジェクト毎に領域が確保されます。
インスタンス化を行い、クラスをインスタンス化すると各オブジェクトの中にそれぞれ固有の領域が確保されるのに対して、
staticオブジェクトはインスタンスオブジェクトと違い、1つのstaticメンバに対し、領域は1つしか確保されません。なので1つ初期化すると別々にオブジェクトを作っていたとしても共有化されているので他のstaticオブジェクトの中身も書き換わってしまうので注意が必要です。
staticの呼び出し
領域の確保に関してstaticとインスタンスの違いは分かったと思います。ではstaticオブジェクトの呼び出し方法についてまとめていきたいと思います。
まず、static変数やstaticメソッドもインスタンス化してから呼び出すことは可能です。
しかし、インスタンスオブジェクトと違い、いくらオブジェクトを作っても、領域は1つしかないため、インスタンス化しなくてもstaticオブジェクトは呼び出せるようになっています。
構文は以下の通り
- クラス名.static変数名 ←static変数の呼び出し
- クラス名.staticメソッド名(); ←staticメソッドの呼び出し
インスタンスみたいにnew~なんて構文は作らなくても上の構文だけで呼び出せるっちゅうことなんですね。(インスタンス化しても問題はなし。)
逆にインスタンスオブジェクトは必ずインスタンス化しなければ呼び出すことができません。
まず問題文やコードを読んだときに、対象先のクラスのフィールドやメソッドにstaticがついているかどうかを確認するのがよさそうですね。
アクセスのルール
staticとインスタンスではそれぞれアクセスの方法が違うことを確認しましたが、アクセスの仕方にもルールがあります。
メンバ間のアクセスのルールは以下の通りです。
- クラス内でアクセスしたインスタンスメンバ同士・staticメンバ同士は直接アクセスできる
- クラス内で定義したインスタンスメンバは、クラス内で定義したstaticメンバに直接アクセスできる
- クラス内で定義したstaticメンバはクラス内で定義したインスタンスメンバに直接アクセスできない。アクセスする場合はインスタンス化してからアクセスする。
もっと簡単に例を挙げます。
インスタンスオブジェクト=staticなし~
staticオブジェクト(クラスオブジェクト)=staticあり~
とします。
- staticなしメソッド ⇒ staticなし変数 = OK
- staticなしメソッド ⇒ staticあり変数 = OK
- staticありメソッド ⇒ staticなし変数 = NG
- staticありメソッド ⇒ staticあり変数 = OK
- staticありメソッドで自クラスをインスタンス化 ⇒ staticなし変数を インスタンス変数名.staticなし変数;でアクセス = OK
これは問題文でひっかけみたいな形ででてくるので覚えたいですね。
直接的なアクセスがダメなだけでアクセスしたい場合はやり方はある感じですね。
ちなみにこのルールでNGになる場合は実行時エラーではなく、コンパイルエラーになります。
クラスオブジェクト(staticありのオブジェクト)のメンバはすべてのインスタンスからアクセス可能であり、すべてのインスタンス菅で共通的に扱われるので上書きしてしまわないように注意が必要ですね。
すごい自由度が高いものだと思います。
ちなみに、インスタンスオブジェクト(staticなし)はクラスオブジェクトのメンバを自分のモノかのように扱える特性もあるみたいです。
どういうことかというと、クラスオブジェクト(staticあり)を呼び出す際にクラス名.staticメソッド名();が基本構文になりますが、インスタンスオブジェクトと共通化されているため、インスタンス変数名.staticメソッド名();でも呼び出すことが可能になるということらしいです。
staticありのクラスオブジェクトへのアクセスはインスタンスを介しても、インスタンス化せずに直接呼び出してもどっちでも問題ないみたいですね。
static/クラスオブジェクトのまとめ
・インスタンスの元となるファイル情報を格納しているメモリ領域をクラスオブジェクトと言い、Javaの実行においてロード(ファイルの読み込み)の際にメモリ上に生成される。
・クラスオブジェクトではファイル情報の他にフィールドとメソッドを保有することが可能であり、フィールドをクラス変数、メソッドをクラスメソッド、合わせて静的メンバと言う。
・static修飾子をつけることで静的メンバとして扱うことが可能。
・staticメンバはJava実行時点で既にメモリ上に存在するため、通常のメンバと違いインスタンス化せずに使用可能
・クラスオブジェクトは変数名としてクラス名が使われる。
このため、クラス変数やクラスメソッドには「クラス名.〇〇」でアクセスが可能。
・静的メンバはクラスオブジェクトで管理されるためインスタンス化の際に複製されない。クラスで固有、すべてのインスタンスで共通のものとして扱われます。
・静的メンバは「インスタンス変数名.〇〇」というように、インスタンスから自身のものであるかのようにアクセスが可能。
コメント