385

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

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ごとにクラスごとに1つの静的インスタンスがあることを覚えておいてください。 - Javamann

21 답변


565

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

だということだのインスタンスは1つだけstaticフィールドが存在します[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つになりますが、それは重要なことです。


  • .NETでは、[ThreadStatic]属性を使用してこの動作を変更することもできます。これにより、静的スレッドを特定のスレッドに対してローカルにします。 - TheSoftwareJedi
  • だから静的はJavaScriptのプロトタイプのようなものですか? - super
  • いいえ、違います。 JSプロトタイプは、スーパークラスに似ています。 - Adriaan Koster
  • 私はこれが古い記事であることを知っていますが、私のような初心者にとってはこれは役に立ちます。stackoverflow.com/questions/7026507/… - user3526905
  • プライベート変数なので、instance.instanceFieldにアクセスできない場合はありませんか。それとも、それ自身のクラス内でオブジェクトをインスタンス化したために有効ですか。再帰的な悪夢のように思えますが、私はJava初心者です。 - Matt Corby

125

これは、Helloには "clock"のインスタンスが1つだけで、 "Hello"クラスのインスタンスごとに1つだけではないことを意味します。つまり、すべてのインスタンス間で共通の "clock"参照が1つになります。 "Hello"クラス

それで、あなたがあなたのコードのどこかで「新しいHello」をすることになっていたら: A - 最初のシナリオ(変更前、「static」を使用せず)では、「new Hello」が呼び出されるたびに新しい時計が作成されますが、 B- 2番目のシナリオ(変更後、 "static"を使用)では、すべての "new Hello"インスタンスは、最初に作成された最初の同じ "clock"参照を引き続き共有して使用します。

あなたがmainの外側のどこかで "clock"を必要としない限り、これは同様にうまくいくでしょう:

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


  • これはそれを行うためのより一般的な方法です。のmain()ルーチンは自己完結型であるべきです。 - Jason S
  • 2番目の例では、mainメソッドが呼び出されるたびにClockの新しいインスタンスが作成されます。 - Click Upvote
  • 2番目のインスタンス、clock staticでは、作成は1回だけです。私の例では、時計がメイン内にある場合、はい、メインが呼び出されるたびに新しく作成されます。しかし、通常mainはプログラム起動時に一度だけ呼び出され、終了するとすべてがフリーになります。 - Paul Tomblin
  • メインメソッドで新しい時計を作成する方法はわかりませんか。あなたが言うように、それはmainが呼ばれるたびにそれを新しいものにするでしょう、しかし唯一のmainメソッドがあります。そのメインメソッドはどのように異なるクロックインスタンスを参照することができますか?メインの時計の新しいインスタンスを作成してそのメソッドsayTime()を使用することがどのように可能であるかを理解するのは少し難しいですが、メインのインスタンスを作成してsayTimeを使用することはできません。 ()。 mainが一度呼び出されると、すべてが無料になりますか。 @PaulTomblin - user5621266
  • @ user5621266私だけを使ったmainOPがやったので方法。代わりに、それが他の場所から呼び出されたパブリックメソッドであり、Helloクラスが複数回インスタンス化されている場合は、各Helloインスタンスに対してClockインスタンスを作成できます。clock静的でした。 - Paul Tomblin

93

staticキーワードは、何か(フィールド、メソッド、またはネストクラス)がタイプ特定のものではなく実例タイプの。そのため、たとえば、Math.sin(...)のインスタンスなしでMathクラス、そして確かにあなたできないのインスタンスを作成しますMathクラス。

詳しくは、OracleのJavaチュートリアルの関連部分


ウィー

残念ながらJava許可するインスタンスメンバーのように静的メンバーにアクセスします。

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

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

// Clearer
Thread.sleep(5000);


  • 別の例:System.out.println()ルックスクラスメソッドと似ていますが、実際にはインスタンスメソッドです。 outはSystemクラスのPrintStreamインスタンスです。 - Jiahui Zhang
  • @LeslieCheung:いいえ、それは私にとってはクラスメソッドのようには見えません。System.out型の名前が好きではありません。 - Jon Skeet

38

staticJavaのキーワードとは、そのクラスのすべてのインスタンス間で変数または関数が共有されることを意味します。タイプ実際の物そのものではありません。

あなたが変数を持っているのであれば:private static int i = 0;そしてあなたはそれを増やす(i++1つの例では、変更はすべての例に反映されます。iすべての場合で1になります。

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


  • "すべてのインスタンス間で共有"間違った印象を与える、IMO - それはあなたがそれを示唆している行うオブジェクトのインスタンスが必要です。 - Jon Skeet
  • (実際には存在する必要はありません)どれか静的フィールドなどは、タイプ。) - Jon Skeet
  • @ Jon Skeet staticはオブジェクトではなくtypeに属しますか?もっと詳しく教えてください。データ型のような型:int、double、...? - truongnm
  • @truongnm:変数/メソッドを宣言するクラスのように入力します。 - Jon Skeet

22

静的メンバーの基本的な使い方

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";


19

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

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クラスのインスタンスごとに異なる値/参照を持つことになるため、クラスの静的部分からはアクセスできませんでした。


15

Javaで静的:

静的は非アクセス修飾子です。 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

この場合、静的変数は一度だけメモリを取得します。オブジェクトが静的変数の値を変更しても、その値は保持されます。

ファイナルスタティック

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

enter image description here

画像リソース:ファイナルスタティック


13

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


  • これはApocalispのMerhdadの回答に対するコメントで言及されていました。 - Zach Langley
  • いい視点ね。多くの人がこれを知らないが、いったんクラスローダーをいじってしまうと、それは非常に重要になる。 - sleske
  • これはすべて真実ですが、質問に答えていません。コメントとして投稿されているはずです。 - user207421

12

既存の回答に追加するには、私は絵を試してみましょう:

2%の金利がすべての普通預金口座に適用されます。だからそれは静的

バランスは個々そうですではない静的。

enter image description here


7

フィールドは、クラスまたはクラスのインスタンスに割り当てることができます。デフォルトでは、フィールドはインスタンス変数です。を使ってstaticフィールドはクラス変数になるので、唯一のものがありますclock。あなたが一箇所で変更を加えた場合、それはいたるところに表示されます。インスタンス変数は互いに独立して変更されます。


6

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

「特定のインスタンスとは関係なく、または関係なく」

あなたが考えるならstaticこのようにして、それが遭遇するさまざまな文脈におけるその使用法を理解することがより簡単になります。

  • Astaticfieldは特定のインスタンスではなくクラスに属するフィールドです。

  • Astaticmethodはの概念がないメソッドですthis;それはクラスで定義されており、参照が渡されない限り、そのクラスの特定のインスタンスについては知りません。

  • Astaticメンバークラスは、その親クラスのインスタンスについての概念や知識がないネストクラスです(親クラスのインスタンスへの参照が渡されない限り)。


5

静的は、クロックメンバーをインスタンスメンバーではなくクラスメンバーにします。 staticキーワードがなければ、Helloクラスのインスタンス(clockメンバ変数を持つ)を作成する必要があります。

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


5

静的メソッドは、それらが定義されているクラスのインスタンス変数を使用しません。違いについての非常に良い説明は、にあります。このページ


  • リンクは機能しなくなりました。 - John

5

私は "ヘルパー"クラスの静的メソッド(可能な場合のみ)を好みます。

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

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


5

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

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

  1. のすべてのフィールドとメソッドを作るHelloそれらが内部で参照できるようにクラスstaticメイン方法。これは実際には良いことではありません(あるいはフィールドやメソッドを静的にする間違った理由)
  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();
    }
}


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

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

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

以下は、静的変数の取得メソッドと設定メソッドの例です。

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

//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
    }
}


0

あるプロジェクトを実行するとき、最初に静的なもの(変数、メソッド、ブロックなど)をロードします。

このプロジェクトを実行すると、最初にメインメソッドがロードされます。それはだからstatic method。それからそれはオブジェクトに見えます"a" object.Butオブジェクトはまだ定義されていません。その非静的だから。その後、このエラーのようになります。

リンクされた質問


関連する質問

最近の質問