質問: staticフィールドについての質問です。 terateilでスレッドの調停時に使うsynchronizedについて質問した時に出た話題からの質問です。(その質問を見なくても、全然大丈夫です) もともとの質問から大きくずれますので、こちらで新たに質問します。 synchronizedでは ``` synchronized(対象インスタンス){} ``` のような表記になります。 そして、以下のようなパターンを目にしました。 ``` synchronized(System.out){} ``` てことはSystem.outってインスタンスということになります。 そのインスタンス化のタイミングは定かではないのですが、このインスタンスの個数は絶対に1つなのでしょうか? 回答者の方が言うには、staticフィールドなので、インスタンスは一つだとのことですが、そうなのですか? ``` public class Family{ static Airconditioner aircon; String name; } ``` のようなコードを考えた時に、staticフィールドのインスタンスはクラスおよびそれから生じるインスタンスに属するような形になるので、一つが自然だとは思うのですが、ルールとして決まっているのでしょうか? 回答お願いします。 みなさん、回答ありがとうございます。 System.outがインスタンスと私が書いているので、皆さんそれを指摘されてますね。 私の使用している参考書にsynchronizedブロックについての次のような記述があります。 synchronized(対象インスタンス){ //複数スレッドから同時実行されないよう保護したいコード } そして、synchronized(System.out)というような記述があるということはSystem.outはインスタンス(正確にはインスタンスの参照)になるのではないでしょうか?
回答: そもそもstaticが何かを理解しないと混乱するばかりでしょう。 まず、「staticではないフィールド」を考えます。 ``` public class A { int a; } ``` このようなクラスAがあったとします。aはstaticではないフィールドです。staticではないので、**このAクラスのインスタンスごとにaは異なる値を取ることができます。** ``` A a1 = new A(); A a2 = new A(); A a3 = new A(); a1.a = 1; a2.a = 2; a3.a = 3; System.out.println("a1.a = " + a1.a); System.out.println("a2.a = " + a2.a); System.out.println("a3.a = " + a3.a); ``` このようなコードを実行してみると、各インスタンスのaの値が異なることが確認できるはずです。 一方、「staticなフィールド」を考えてみましょう。 ``` public class B { static int b; } ``` このようなクラスBを考えます。このbはstaticフィールドです。staticフィールドは**そのクラスに唯一の存在であり、インスタンスとは独立した領域にメモリを取ります。** ``` B b1 = new B(); B b2 = new B(); b1.b = 1; System.out.println("b1.b = " + b1.b); System.out.println("b2.b = " + b2.b); ``` このようなコードを実行したとします。途中b1インスタンスからbを変更しました。b2は生成してから何も操作していません。普通に考えたら、2行目でb2.bを出力した結果は初期状態の0であるように思われるかもしれません。しかし**bはBクラス唯一の変数であり**、b1からでもb2からでも同じ変数を指します。つまり、b1からだけbを操作したつもりでも、そのbはb2から見ても同じ変数のため、出力結果はどちらも「1」になります。 このようにstatic変数はインスタンスとは切り離されたものであり、それをインスタンスから操作・参照するのは整合性が悪いので、staticなフィールドやメソッド(フィールドやメソッドをまとめて**メンバ**と呼ぶ)は`クラス名.メンバ`と書くことが推奨されています。 話を戻すと、System.outはクラス唯一の変数です。そのため、どこからアクセスしようと`System.out`という変数はただひとつしか存在しないのです。「変数」と言っていますが、このSystem.outはその型がPrintStream型であるというだけの話です。