クラスで 'static'キーワードは何をしますか?


444

具体的には、私はこのコードを試していました:

package hello;

public class Hello {

    Clock clock = new Clock();

    public static void main(String args[]) {
        clock.sayTime();
    }
}

しかし、それはエラーを与えました

静的メソッドmainの非静的フィールドにアクセスできません

だから私はの宣言をこれに変更しましたclock

static Clock clock = new Clock();

そしてそれはうまくいった。宣言の前にそのキーワードを置くとはどういう意味ですか?そのオブジェクトに対して何を実行できるかに関して、正確に何を行うか、または制限するか?


もう一度、CLASSLOADERごとにクラスごとにstaticのインスタンスが1つあることを思い出してください。
Javamann、2009年

回答:


633

static メンバーは特定のインスタンスではなくクラスに属しています。

つまり、クラスのインスタンスを100万個作成した場合でも、作成しなかった場合でもstaticフィールドのインスタンスは1つしか存在しません[1]。すべてのインスタンスで共有されます。

以来staticの方法はまた、特定のインスタンスに属していない、彼らはインスタンスメンバを参照することはできません。与えられmainた例では、Helloクラスのどのインスタンス(したがってクラスのどのインスタンスClock)を参照すべきかわかりません。staticメンバーはメンバーのみを参照できstaticます。もちろん、インスタンスメンバーはメンバーにアクセスできますstatic

補足:もちろん、staticメンバーはオブジェクト参照を通じてインスタンスメンバーにアクセスできます。

例:

public class Example {
    private static boolean staticField;
    private boolean instanceField;
    public static void main(String[] args) {
        // a static method can access static fields
        staticField = true;

        // a static method can access instance fields through an object reference
        Example instance = new Example();
        instance.instanceField = true;
    }

[1]:ランタイムの特性に応じて、ClassLoader、AppDomain、またはスレッドごとに1つになる可能性がありますが、それは重要ではありません。


5
.NETでは、[ThreadStatic]属性を使用してこの動作を変更することもできます。これにより、静的が特定のスレッドに対してローカルになります。
TheSoftwareJedi 2009年

4
私はこれが古い記事であることを知っていますが、私のような初心者にとってはこれが役に立つかもしれません。stackoverflow.com/questions/7026507/...
user3526905

プライベート変数なので、instance.instanceFieldにアクセスできませんか?または、それ自体のクラス内でオブジェクトをインスタンス化したので、それは有効ですか?再帰的な悪夢のように聞こえますが、私はJava初心者です。
Matt Corby

クラスの静的メンバーが2つの異なるスレッドによって参照されている場合、その静的メンバーのインスタンスはいくつありますか?2だと思いますが、スレッド間で同じインスタンスが必要な場合は、volatileキーワードを使用する必要があります。あれは正しいですか?
Dan

..そして、クラスのインスタンスが残っていない場合、値は保持されますか?
mckenzm

130

これは、Helloには「クロック」のインスタンスが1つしかなく、「Hello」クラスの個別のインスタンスごとに1つではないことを意味します。つまり、 「Hello」クラス。

したがって、コード内の任意の場所で「新しいHello」を実行する場合:A-最初のシナリオ(変更前、「静的」を使用しない)では、「新しいHello」が呼び出されるたびに新しい時計が作成されます。ただし、B- 2番目のシナリオ(変更後、「静的」を使用)では、すべての「新しいHello」インスタンスは、最初に作成された最初の同じ「クロック」参照を引き続き共有して使用します。

メイン以外の場所に「クロック」が必要でない限り、これも同様に機能します。

package hello;
public class Hello
{
    public static void main(String args[])
    {
      Clock clock=new Clock();
      clock.sayTime();    
    }
}

これは、より一般的な方法です。main()ルーチンは、自己完結型でなければなりません。
Jason S

1
2番目のインスタンスでは、mainメソッドが呼び出されるたびにClockの新しいインスタンスを作成しますよね?
2009年

2
2番目のインスタンスであるクロックスタティックでは、作成は1回だけです。クロックがメイン内にある私の例では、はい、メインが呼び出されるたびに新しいクロックが作成されます。しかし、通常、mainはプログラムの起動時に一度だけ呼び出され、終了するとすべて解放されます。
ポールトンブリン

mainメソッドで新しい時計を作成することはできますか?あなたが言うように、それはmainが呼び出されるたびに新しく作成されますが、mainメソッドは1つだけです。その主な方法はどのように異なるクロックインスタンスを参照できますか?メインで時計の新しいインスタンスを作成し、sayTime()メソッドを使用する方法を理解するのは少し難しいですが、インスタンスをメインから作成してsayTime()を使用することはできません。mainが一度呼び出されると、すべてがどのように解放されますか?@PaulTomblin
ShakibaZar

@ user5621266 mainOPで使用されたため、このメソッドのみを使用しました。代わりに、それが他の場所から呼び出されたパブリックメソッドであり、Helloクラスが複数回インスタンス化されている場合、clock静的でない限り、各HelloインスタンスにClockインスタンスを作成できます。
Paul Tomblin

97

staticキーワード手段は何か(フィールド、メソッドまたはネストされたクラス)と関連しているタイプではなく、任意の特定のインスタンスのタイプの。したがって、たとえば、クラスのMath.sin(...)インスタンスなしで1回の呼び出しを行うMathと、実際にはクラスのインスタンスを作成できませんMath

詳細については、OracleのJavaチュートリアルの関連する部分を参照してください。


サイドノート

残念ながら Java では静的メンバーにインスタンスメンバーのようにアクセスできます。

// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);

それはそれは作る見ているかのようにsleepインスタンスメソッドであるが、それは実際には、静的メソッドだ-それは、常に現在のスレッドの睡眠を作ります。呼び出しコードでこれを明確にすることをお勧めします。

// Clearer
Thread.sleep(5000);

1
別の例:System.out.println()クラスメソッドのように見えますが、実際にはインスタンスメソッドです。outはSystemクラスのPrintStreamインスタンスなので、
Jiahui Zhang

@LeslieCheung:いいえ、System.outタイプ名が好きではないので、クラスメソッドのようには見えません。
Jon Skeet

42

staticJava のキーワードは、変数または関数が実際のオブジェクト自体ではなくtypeに属しているため、そのクラスのすべてのインスタンス間で共有されることを意味します。

したがって、変数がある場合、1つのインスタンスで変数private static int i = 0;をインクリメント(i++)すると、変更はすべてのインスタンスに反映されます。iすべてのインスタンスで1になります。

静的メソッドは、オブジェクトをインスタンス化せずに使用できます。


4
「すべてのインスタンス間で共有」は誤った印象を与えます、IMO- オブジェクトのインスタンスが必要であることを示唆してます。
Jon Skeet、

1
(一方で、本当にがあるように必要のない任意の静的フィールドなどがに属しているため、インスタンスタイプ。)
ジョンスキート

@Jon Skeet staticはオブジェクトではなくタイプに属していますか?詳細を教えてください。データ型のような型:int、double、...?
truongnm

@truongnm:変数/メソッドを宣言するクラスのように入力します。
Jon Skeet

26

静的メンバーの基本的な使用法...

public class Hello
{
    // value / method
    public static String staticValue;
    public String nonStaticValue;
}

class A
{
    Hello hello = new Hello();
    hello.staticValue = "abc";
    hello.nonStaticValue = "xyz";
}

class B
{
    Hello hello2 = new Hello(); // here staticValue = "abc"
    hello2.staticValue; // will have value of "abc"
    hello2.nonStaticValue; // will have value of null
}

これにより、クラスインスタンスHelloを他のクラスに送信せずに、すべてのクラスメンバーで値を共有できます。そして、静的なクラスインスタンスを作成する必要はありません。

Hello hello = new Hello();
hello.staticValue = "abc";

クラス名で静的な値またはメソッドを呼び出すだけです。

Hello.staticValue = "abc";

22

静的とは、クラスに関連付けられたメソッドまたは変数を使用するためにクラスのインスタンスを作成する必要がないことを意味します。あなたの例では、あなたは呼び出すことができます:

Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class

直接、代わりに:

Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the "h" variable

(クラスに属する)静的メソッドの内部からは、静的でないメンバーにはアクセスできません。それらの値はクラスのインスタンス化に依存するためです。インスタンスメンバーである非静的Clockオブジェクトは、Helloクラスのインスタンスごとに異なる値/参照を持つため、クラスの静的部分からアクセスすることはできません。


静的コンテキストの
優れた

20

Javaの静的:

Staticは非アクセス修飾子です。staticキーワードは、クラスのインスタンスよりもクラスに属しています。クラスに変数またはメソッドをアタッチするために使用できます。

静的キーワードは以下で使用できます:

方法

変数

別のクラス内にネストされたクラス

初期化ブロック

次のものでは使用できません:

クラス(ネストされていない)

コンストラクタ

インターフェース

メソッドローカル内部クラス(違いとネストされたクラス)

内部クラスメソッド

インスタンス変数

ローカル変数

例:

コンストラクターでインクリメントされるcountという名前のインスタンス変数を持つ次の例を想像してください。

package pkg;

class StaticExample {
    int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

出力:

1 1 1

インスタンス変数はオブジェクトの作成時にメモリを取得するため、各オブジェクトはインスタンス変数のコピーを保持します。インクリメントされると、他のオブジェクトに反映されません。

インスタンス変数の数を静的なものに変更すると、プログラムは異なる出力を生成します。

package pkg;

class StaticExample {
    static int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

出力:

1 2 3

この場合、静的変数はメモリを1回だけ取得し、オブジェクトが静的変数の値を変更した場合、その値を保持します。

ファイナル付きスタティック:

finalとstaticとして宣言されているグローバル変数は、実行全体を通して変更されません。静的メンバーはクラスメモリに格納され、実行全体で一度だけロードされるためです。それらはクラスのすべてのオブジェクトに共通です。static変数をfinalとして宣言すると、オブジェクトはfinalなので値を変更できません。したがって、finalおよびstaticとして宣言された変数は、定数と呼ばれることがあります。インターフェイスのすべてのフィールドは、デフォルトで最終的で静的であるため、定数と呼ばれます。

ここに画像の説明を入力してください

画像リソース:最終的な静的


15

既存の回答に追加するには、画像で試してみましょう:

すべての普通預金口座には2%の金利が適用されます。したがって、静的です。

バランスは個別でなければならないため、静的ではありません

ここに画像の説明を入力してください


13

この説明では、これまでのところクラスローダーの考慮事項を無視しています。厳密に言うと、Java静的フィールドは、指定されたクラスローダーのクラスのすべてのインスタンス間で共有されます。


1
これは、メルダッドの答えに関するコメントでアポカリスプによって言及されました。
Zach Langley、

1
いい視点ね。多くの人はこれを知らないでしょうが、クラスローダーをいじり始めると、それは非常に重要になります。
sleske 2009年

2
これはすべて真実ですが、質問には答えません。コメントとして投稿されているはずです。
ローンの侯爵

7

フィールドは、クラスまたはクラスのインスタンスのいずれかに割り当てることができます。デフォルトでは、フィールドはインスタンス変数です。staticフィールドを使用すると、クラス変数になるため、は1つだけ存在しclockます。1か所で変更を加えると、どこにでも表示されます。インスタンス変数は、互いに独立して変更されます。


6

キーワードstaticは、フィールドまたはメソッドをインスタンスではなくクラス自体に属するものとして示すために使用されます。コードを使用して、オブジェクトClockが静的である場合、HelloクラスのすべてのインスタンスがこのClockデータメンバー(フィールド)を共有します。非静的にすると、の個々のインスタンスにHello一意のClockフィールドを設定できます。

問題は、コードを実行できるようにクラスにメインメソッドを追加したHelloことです。ここでの問題は、メインメソッドが静的であるため、内部の非静的フィールドまたはメソッドを参照できないことです。これは2つの方法で解決できます。

  1. メインメソッドHello内で参照できるように、クラスのすべてのフィールドとメソッドを静的にします。これは本当に良いことではありません(またはフィールドやメソッドを静的にする間違った理由)
  2. Helloメインメソッド内にクラスのインスタンスを作成し、すべてのフィールドとメソッドに本来の方法でアクセスします。

あなたにとって、これはあなたのコードへの以下の変更を意味します:

package hello;

public class Hello {

    private Clock clock = new Clock();

    public Clock getClock() {
        return clock;
    }

    public static void main(String args[]) {
        Hello hello = new Hello();
        hello.getClock().sayTime();
    }
}

6

Javaでは、staticキーワードは単に以下を示すと見なすことができます。

「特定のインスタンスに関係なく」

このように考えるとstatic、さまざまな状況での使用が理解しやすくなります。

  • staticフィールドは、クラスではなく、任意の特定のインスタンスに属している分野であります

  • staticこの方法は、という概念を持っていない方法ですthis。クラスで定義されており、参照が渡されない限り、そのクラスの特定のインスタンスについては認識しません

  • static(封入クラスインスタンスへの参照が、それに渡されていない限り)メンバクラスは、その囲みクラスのインスタンスのいずれかの概念や知識なしネストされたクラスであります


5

Staticは、クロックメンバーをインスタンスメンバーではなくクラスメンバーにします。staticキーワードがない場合は、Helloクラスのインスタンス(クロックメンバー変数を持つ)を作成する必要があります。たとえば、

Hello hello = new Hello();
hello.clock.sayTime();


5

「ヘルパー」クラスで静的メソッド(可能であれば)の好みを開発しました。

呼び出し元のクラスは、ヘルパークラスの別のメンバー(インスタンス)変数を作成する必要はありません。ヘルパークラスのメソッドを呼び出すだけです。また、コンストラクターが不要になり、メンバー(インスタンス)変数が不要になるため、ヘルパークラスも改善されます。

おそらく他の利点があります。


4
//Here is an example 

public class StaticClass 
{
    static int version;
    public void printVersion() {
         System.out.println(version);
    }
}

public class MainClass 
{
    public static void main(String args[]) {  
        StaticClass staticVar1 = new StaticClass();
        staticVar1.version = 10;
        staticVar1.printVersion() // Output 10

        StaticClass staticVar2 = new StaticClass();
        staticVar2.printVersion() // Output 10
        staticVar2.version = 20;
        staticVar2.printVersion() // Output 20
        staticVar1.printVersion() // Output 20
    }
}

3

"this"ポインターがない静的メンバーも考えられます。それらはすべてのインスタンス間で共有されます。


3

静的な概念を理解する

public class StaticPractise1 {
    public static void main(String[] args) {
        StaticPractise2 staticPractise2 = new StaticPractise2();
        staticPractise2.printUddhav(); //true
        StaticPractise2.printUddhav(); /* false, because printUddhav() is although inside StaticPractise2, but it is where exactly depends on PC program counter on runtime. */

        StaticPractise2.printUddhavsStatic1(); //true
        staticPractise2.printUddhavsStatic1(); /*false, because, when staticPractise2 is blueprinted, it tracks everything other than static  things and it organizes in its own heap. So, class static methods, object can't reference */

    }
}

セカンドクラス

public class StaticPractise2 {
    public static void printUddhavsStatic1() {
        System.out.println("Uddhav");
    }

    public void printUddhav() {
        System.out.println("Uddhav");
    }
}

2

main() は2つの基本的な制限がある静的メソッドです。

  1. 静的メソッドは、非静的データメンバーを使用したり、非静的メソッドを直接呼び出すことはできません。
  2. this()そしてsuper()、静的コンテキストで使用することはできません。

    class A {  
        int a = 40; //non static
        public static void main(String args[]) {  
            System.out.println(a);  
        }  
    }

出力:コンパイル時エラー


1

静的変数は静的メソッドでのみアクセスできるため、静的変数を宣言すると、これらのゲッターメソッドとセッターメソッドは静的メソッドになります。

静的メソッドは、クラス名を使用してアクセスできるクラスレベルです。

以下は、静的変数のゲッターとセッターの例です。

public class Static 
{

    private static String owner;
    private static int rent;
    private String car;
    public String getCar() {
        return car;
    }
    public void setCar(String car) {
        this.car = car;
    }
    public static int getRent() {
        return rent;
    }
    public static void setRent(int rent) {
        Static.rent = rent;
    }
    public static String getOwner() {
        return owner;
    }

    public static void setOwner(String owner) {
        Static.owner = owner;
    }

}

1

ここでは、この概念に対する「静的」という単語の選択について質問さました。それはこの質問にふさわしかったが、語源が明確に扱われたとは思わない。そう...


これは、Cから始まるキーワードの再利用によるものです。

Cでのデータ宣言を検討してください(関数本体内):

    void f() {
        int foo = 1;
        static int bar = 2;
         :
    }

変数fooは、関数に入るときにスタックに作成されます(関数が終了すると破棄されます)。対照的に、barは常に存在するため、一般的な英語の意味では「静的」であり、どこにも行きません。

Java、および類似の言語は、データに対して同じ概念を持っています。データは、クラスのインスタンスごと(オブジェクトごと)またはクラス全体に1回割り当てることができます。JavaはC / C ++プログラマにとって使い慣れた構文を持つことを目的としているため、ここでは 'static'キーワードが適切です。

    class C {
        int foo = 1;
        static int bar = 2;
         :
    }

最後に、メソッドについて説明します。

    class C {
        int foo() { ... }
        static int bar() { ... }
         :
    }

概念的に言えば、クラスCのインスタンスごとにfoo()のインスタンスがあります。クラスC全体に対してbar()のインスタンスは1つしかありません。これは、データについて説明した場合と同じであるため、「静的'は、特に予約語を言語に追加したくない場合は、賢明な選択です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.