質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.77%

staticフィールドについて

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,980
退会済みユーザー

退会済みユーザー

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はインスタンス(正確にはインスタンスの参照)になるのではないでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+1

そもそも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型であるというだけの話です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/23 11:37

    その通りだと思いますが、
    「newでPrintStreamインスタンスを複数生成しても、outが参照するPrintStreamインスタンスは一つである」
    という文章の何がおかしいのでしょうか?
    System.outがfinalであるかどうかにかかわらず、PrintStreamクラスのインスタンスは生成することができます。
    もちろん、生成したインスタンスをSystemクラスのstatic変数outが参照することはできませんが。(finalであるため)

    キャンセル

  • 2016/08/23 11:49

    そもそもなぜそんな話が出てきたのかがよくわかりません。outにかぎらず、いかなる状況でも同じ型のインスタンスをいくつ生成しようと、その変数に代入しないかぎり参照するインスタンスに変化はありません。

    キャンセル

  • 2016/08/23 12:38

    回答ありがとうございました。

    キャンセル

+1

てことはSystem.outってインスタンスということになります。 

この表現がよくわからないですが、
インスタンス変数にはインスタンスへの参照が入っていて、厳密に言えばインスタンスそのものではありません。

staticメンバはクラスに所属するような振る舞いとなるので、そのクラスから生じるインスタンスは関係ありません。
この意味ではstaticメンバ自体はアプリケーション内で一つと言えます。

どのインスタンスが用いられるかは、実行時、そのstaticメンバにどのインスタンスへの参照が入っているか次第です。
言語仕様なのでルールですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/22 15:14

    私の理解では、outは参照型の変数でPrintStream型のインスタンスを参照しており、static変数だから、クラスに属する形になっており、outが参照するPrintStreamインスタンスは(PrintStreamインスタンスが複数存在したとしても)常に一つである。
    というような理解なのですが、どうでしょうか?

    キャンセル

  • 2016/08/22 15:44

    ちょっと「複数存在したとしても」のあたりが回りくどいけどそうですね。

    キャンセル

  • 2016/08/23 12:38

    回答ありがとうございました。

    キャンセル

0

synchronized(対象インスタンス){}


そもそもこれ本当ですか?と思って仕様を確認しましたが、

SynchronizedStatement:
    synchronized ( Expression ) Block
  The type of Expression must be a reference type, or a compile-time error occurs. 

としか書かれていません。どこにも「インスタンス」などという名前は出て来てないきがしますが。
reference typeとは参照型、つまり「オブジェクト」の事であってあらゆるオブジェクトが該当しますよね。
インスタンスももちろん、クラスだってオブジェクトです。実際

synchronized(Object.class){}


これでコンパイルエラーは発生しません。これは単に「何をキーにロック管理するか」だけの話であろうかと思うのですが。

ちなみに、

System.out.println(System.out.getClass());


の結果は

class java.io.PrintStream


です。つまり「System.outはPrintStreamのインスタンスです」と思うのですが・・・
いかがでしょうか。

「対象インスタンス」という文言の意図は、単に「それが当てはめられる事が多い」程度の意味ではありませんか?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/23 11:56

    そうです。全てオブジェクト。それがオブジェクト指向です。

    キャンセル

  • 2016/08/23 11:59

    SystemもSystem.outもオブジェクトです。SystemがSystem.outを参照している。それだけです。

    キャンセル

  • 2016/08/23 12:02

    おうたがいなら、
    System.class instanceOf Object

    してみてください。

    キャンセル

-4

synchronized(System.out){}

てことはSystem.outってインスタンスということになります。 

どうしてそうなるのか。
synchronizedは、スレッドに関する命令でインスタンスとは関係ありません。

System (Java Platform SE 8 ) を見ればわかりますが、

Systemクラスには有用なクラス・フィールドおよびメソッドがあります。インスタンス化することはできません。

とあります。outフィールドは、staticと宣言されているので、インスタンスではありません。

staticに対してインスタンスという言葉を使うこと自体が間違ってます。
staticフィールドは、クラスがロードされた時点で初期化されます。
ひとつしか用意されません。ルールというより仕様として決まっています。

インスタンスフィールドというのは、new命令によって
クラスのインスタンスが作成されるた時に初期化されます。
なので、インスタンス化された分だけ存在します。

もう一度言います、staticフィールドは、インスタンスフィールドではありません。

staticフィールドは、クラスに属するもの
インスタンスフィールドは、インスタンス化されたオブジェクトに属するものです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/22 22:45

    まず、あなたの言う「インスタンス」とは「インスタンスの参照」で間違いないですか?

    staticフィールドでもインスタンスの参照は指定できると思うのですが、「インスタンス化されていないクラスのフィールドがインスタンスであるわけがない」の意味するところが理解できません。

    キャンセル

  • 2016/08/22 22:53

    これ以上説明できません。ギブアップです。

    単に知識不足です、Javaの基礎の本を10冊くらい読みましょう。
    プログラムを1万行くらい書きましょう。 以上

    キャンセル

  • 2016/08/23 10:15

    私から見て、あなたの回答も的を外しているように感じます。
    「staticだからインスタンスではあり得ない」というのはおかしな話です。
    結論から言うなら、System.outはPrintStreamクラスのインスタンスを指す変数になります。
    変数がインスタンスか否かというのは、staticかどうかということとは全く無関係です。
    「インスタンスではない」ということと、「インスタンスフィールドではない」ということもまた違う話です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る