staticの罠

このレッスンでは、static とインスタンスの間で何を参照できて何を参照できないのかを判定できるようになります。

まず予測してください

class Counter { static int created; int id; static String report() { return "created=" + created + ",id=" + id; // ここは通る? } }

答えはコンパイルエラーです。static メソッドの中から、インスタンスフィールドである id を名前だけで書くことはできません。

向きによって可否が変わる

この規則は片側通行です。表にすると次のようになります。

見る側見られる側可否
static メソッドstatic フィールド
static メソッドインスタンスフィールド不可
インスタンスメソッドstatic フィールド
インスタンスメソッドインスタンスフィールド

理由は所属先の違いです。static メンバはクラスに1つだけ存在し、インスタンスが1つも作られていなくても使えます。一方インスタンスメンバは「どのインスタンスの分か」が決まらないと値が定まりません。static メソッドはその「どの」に当たる情報を持っていないので、書けないのです。

直し方は2つ

  1. インスタンスを引数で受け取るstatic String report(Counter c) にして c.id と書く
  2. インスタンスメソッドにするstatic を外せば自分自身の id を見られる

どちらでも動きますが、試験では1つ目の形で「引数で受け取れば触れる」ことを確かめさせる出題が多いです。

this と super も static では使えない

同じ理由で、static メソッドの中では thissuper も書けません。「対象のインスタンスがない」という一点から、すべてが説明できます。逆にインスタンスメソッドから static フィールドを触るのは自由です。むしろ this.created のようにインスタンス経由でも書けてしまうので、読み手が static だと気づきにくい書き方として出題されることがあります。

static は共有されている

もう1つの定番が、static フィールドがすべてのインスタンスで共有されている点です。

Counter a = new Counter(); // created は 1 Counter b = new Counter(); // created は 2 System.out.println(a.created); // 2 が出る

a.created と書いても、実体は Counter.created 1つきりです。インスタンスごとに別の値を持っているように見せる選択肢が用意されるので、引っ掛からないようにしてください。

演習で確かめます

コンパイルできない report を、引数でインスタンスを受け取る形に直します。

要件

  1. report は Counter を引数で受け取り、created と id を created=3,id=3 の形でつないで返すこと
  2. check の先頭で Counter.created を 0 に戻すこと
  3. check は Counter を n 個作り、最後に作ったインスタンスを report に渡した結果を返すこと

入出力例

check(3)"created=3,id=3" check(1)"created=1,id=1" check(5)"created=5,id=5"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.java
学習モード

メモ

staticの罠

⌘S で保存