非静的変数は静的コンテキストから参照できません


288

私はこのテストコードを書きました:

class MyProgram
{
    int count = 0;
    public static void main(String[] args)
    {
        System.out.println(count);
    }
}

ただし、次のエラーが発生します。

Main.java:6: error: non-static variable count cannot be referenced from a static context
        System.out.println(count);
                           ^

メソッドにクラス変数を認識させるにはどうすればよいですか?


可能な限りstaticを使用しないようにしてください。のように、完全に静的な完全なプログラム作成できますC。しかし、それはあまり良いものではありません。オブジェクト指向言語として、Javaの本来の使用方法を試してください。
エリックG.ハグストロム

回答:


294

クラスとそのクラスのインスタンスの違いを理解する必要があります。路上で車を見ると、どのモデルやタイプかわからなくても、それが車であることがすぐにわかります。これは、目にするものをクラス「車」と比較するためです。クラスには、すべての車に類似したものが含まれます。テンプレートまたはアイデアと考えてください。

同時に、あなたが見る車はクラス "車"のインスタンスです。それはあなたが期待するすべての特性を持っているからです:誰かがそれを運転していて、それはエンジンと車輪を持っています。

したがって、クラスは「すべての車に色がある」と言い、インスタンスは「この特定の車は赤です」と言います。

オブジェクト指向の世界では、クラスを定義し、クラスの内部ではtypeのフィールドを定義しますColor。クラスがインスタンス化されるとき(特定のインスタンスを作成するとき)、メモリは色のために予約され、この特定のインスタンスに色を与えることができます。これらの属性は固有であるため、静的ではありません。

静的フィールドとメソッドはすべてのインスタンスで共有されます。これらは、特定のインスタンスではなく、クラスに固有の値用です。メソッドの場合、これは通常グローバルヘルパーメソッド(などInteger.parseInt())です。フィールドの場合、それは通常定数です(車のタイプ、つまり、頻繁に変更されない限られたセットがある場合)。

問題を解決するには、ランタイムがインスタンスのメモリを予約できるように、クラスのインスタンスをインスタンス化(オブジェクトを作成)する必要があります(そうしないと、異なるインスタンスが不要なインスタンスを上書きしてしまいます)。

あなたの場合、開始ブロックとしてこのコードを試してください:

public static void main (String[] args)
{
    try
    {
        MyProgram7 obj = new MyProgram7 ();
        obj.run (args);
    }
    catch (Exception e)
    {
        e.printStackTrace ();
    }
}

// instance variables here

public void run (String[] args) throws Exception
{
    // put your code here
}

新しいmain()メソッドは、それが含むクラスのインスタンスを作成し(奇妙に聞こえますが、インスタンスではmain()なくクラスで作成されるため、これを実行できます)、インスタンスメソッドを呼び出します(run())。


現在、これを私たちの新しい同僚に説明しています-この素晴らしい説明に感謝します。これは受理者が答えるべきです。
Supahupe

83

静的フィールドとメソッドは、インスタンスではなくクラス自体に接続されます。あなたはクラスがある場合はA、「通常の」方法b、および静的メソッドをc、そしてあなたは、インスタンス作成aクラスのをA、への呼び出しA.c()とはa.b()有効です。メソッドc()はどのインスタンスが接続されているかを認識していないため、非静的フィールドを使用できません。

あなたのための解決策は、フィールドを静的にするか、メソッドを非静的にすることです。この場合、メインは次のようになります。

class Programm {

    public static void main(String[] args) {
        Programm programm = new Programm();
        programm.start();
    }

    public void start() {
        // can now access non-static fields
    }
}

54

staticキーワードは、クラス内のメソッドまたは変数のライフサイクルを変更します。staticメソッドや変数は、クラスがロードされる時に作成されます。として宣言されていないメソッドまたは変数はstatic、たとえばnew演算子を使用して、クラスがオブジェクトとしてインスタンス化されたときにのみ作成されます。

広義のクラスのライフサイクルは次のとおりです。

  1. クラスのソースコードは、テンプレート、パターン、またはスタンプを作成して記述されます。
  2. newクラスを使用して演算子を使用してオブジェクトを作成し、クラスのインスタンスを実際のオブジェクトとして作成します。
  3. ガベージコレクション中にメモリなどの保持しているリソースを再利用してオブジェクトを破棄します。

アプリケーションの初期エントリポイントを持つために、Javaは、Javaプログラムには、合意された名前または特別な名前のメソッドを含むクラスが必要であるという規則を採用しています。この特別なメソッドはと呼ばれmain()ます。メソッドは、メインメソッドを含むクラスがインスタンス化されているかどうかに関係なく存在するmain()必要があるstaticため、クラスが読み込まれるとすぐにmain()メソッドを使用できるように、修飾子を使用してメソッドを宣言する必要があります。

その結果java helloworld、一連のアクションなどのコマンドラインでJavaアプリケーションを起動すると、発生します。まず、Java仮想マシンを起動して初期化します。次に、コンパイルされたJavaコードを含むhelloworld.classファイルがJava仮想マシンにロードされます。次に、Java仮想マシンは、helloworld呼び出されたクラス内のメソッドを探しmain(String [] args)ます。このメソッドはstatic、クラスが実際にオブジェクトとしてインスタンス化されていなくても存在できるようにする必要があります。Java仮想マシンは、クラスからオブジェクトを作成することによってクラスのインスタンスを作成しません。クラスをロードし、main()メソッドで実行を開始するだけです。

したがって、クラスのインスタンスをオブジェクトとして作成する必要があり、static修飾子で宣言されていないクラスのメソッドと変数にアクセスできます。Javaプログラムがmain()関数で開始されると、staticロードされるクラスの一部として存在するため、修飾子を持つ変数またはメソッドを使用できます。

ただし、メソッドの外部にmain()あり、static修飾子を持たないクラスの変数とメソッドは、クラスのインスタンスがmain()メソッド内のオブジェクトとして作成されるまで使用できません。オブジェクトを作成した後、オブジェクトの変数とメソッドを使用できます。クラスstaticのオブジェクトを経由せずに修飾子を持たないクラスの変数とメソッドを使用しようとすると、コンパイル時にJavaコンパイラーによってキャッチされ、エラーとしてフラグが立てられます。

import java.io.*;

class HelloWorld {
    int myInt;      // this is a class variable that is unique to each object
    static int myInt2;  // this is a class variable shared by all objects of this class

    static void main (String [] args) {
        // this is the main entry point for this Java application
        System.out.println ("Hello, World\n");
        myInt2 = 14;    // able to access the static int
        HelloWorld myWorld = new HelloWorld();
        myWorld.myInt = 32;   // able to access non-static through an object
    }
}

11

最初にプログラムを分析しましょう。プログラムでは、最初のメソッドはmain()であり、静的メソッドであることを覚えておいてください...次に、そのメソッドのローカル変数(compareCount、low、highなど)を宣言します。この変数のスコープは、静的メソッドであるか非静的メソッドであるかに関係なく、宣言されたメソッドのみです。したがって、それらの変数をそのメソッドの外で使用することはできません。これは、uが行った基本的なエラーです。

次に、次のポイントに進みます。あなたは静電気があなたを殺していると言いました。(それはあなたを殺すかもしれませんが、それはあなたのプログラムに命を与えるだけです!)最初にあなたは基本的なことを理解しなければなりません。*静的メソッドは静的メソッドのみを呼び出し、静的変数のみを使用します。*静的変数または静的メソッドは、そのクラスのインスタンスに依存していません。(つまり、静的変数の状態を変更すると、クラスのすべてのオブジェクトに反映されます)*このため、クラス変数またはクラスメソッドとして呼び出します。そして、「静的」キーワードについては、もっとたくさんあります。私は今あなたがアイデアを得ることを望みます。最初に変数のスコープを変更し、それを静的として宣言します(静的メソッドで使用できるようにするため)。

そしてあなたへのアドバイスは、あなたは変数と静的機能のスコープの考えを誤解しました。それについて明確な考えをつかんでください。


11

非常に基本的なことは、静的変数または静的メソッドがクラスレベルにあることです。クラスレベルの変数またはメソッドは、インスタンスレベルのメソッドまたは変数の前にロードされます。ロードされていないものは使用できません。したがって、Javaコンパイラーは、実行時に処理されるものを許可しないため、コンパイル時に解決されます。そのため、静的でないコンテキストから静的なものを参照できないエラーが発生します。クラスレベルのスコープ、インスタンスレベルのスコープ、ローカルスコープについてお読みください。


8

静的メソッドからそれらにアクセスできるようにするには、次のように静的メンバー変数である必要があります。

public class MyProgram7 {
  static Scanner scan = new Scanner(System.in);
  static int compareCount = 0;
  static int low = 0;
  static int high = 0;
  static int mid = 0;  
  static int key = 0;  
  static Scanner temp;  
  static int[]list;  
  static String menu, outputString;  
  static int option = 1;  
  static boolean found = false;

  public static void main (String[]args) throws IOException {
  ...

7

メソッドでインスタンスを追加/使用できるようになりました

public class Myprogram7 {

  Scanner scan;
  int compareCount = 0;
  int low = 0;
  int high = 0;
  int mid = 0;  
  int key = 0;  
  Scanner temp;  
  int[]list;  
  String menu, outputString;  
  int option = 1;  
  boolean found = false;  

  private void readLine() {

  }

  private void findkey() {

  }

  private void printCount() {

  }
  public static void main(String[] args){

    Myprogram7 myprg=new Myprogram7();
    myprg.readLine();
    myprg.findkey();
    myprg.printCount();
  }
}

複雑なsrcファイルを適切な構造に修正するためのテンプレートとして使用した非常に確かな例。
XMAN 2018年

3

静的なことを説明しようと思います。まず、静的変数はクラスの特定のインスタンスに属していません。クラスの名前で認識されます。静的メソッドは、再び特定のインスタンスに属しません。静的変数にのみアクセスできます。MyClass.myMethod()を呼び出し、myMethodが静的メソッドであるとします。メソッド内で非静的変数を使用する場合、どのような変数を使用するか、一体一体どうやって知るのでしょうか?これが、静的メソッドから静的変数のみを使用できる理由です。繰り返しますが、それらは特定のインスタンスに属していません。


2
  • 最初に、クラスのインスタンスとクラス自体の違いを理解します。クラスは、特定のプロパティと、それらのプロパティのコンテキストでの全体の動作をモデル化します。インスタンスは、これらのプロパティの特定の値を定義します。

  • staticキーワードにバインドされたものはすべて、クラスのインスタンスのコンテキストではなく、クラスのコンテキストで使用できます

  • 上記の結果として

    1. メソッド内の変数は静的であってはなりません
    2. 静的フィールド、およびメソッドはクラス名を使用して呼び出す必要があります。例:MyProgram7.main(...)
  • 静的フィールド/メソッドの存続期間は、アプリケーションの存続期間と同等です

たとえば、車はプロパティの色を持ち、「動き」の動作を示します。車のインスタンスは、25kmphで動いている赤いフォルクスワーゲンのビートルでしょう。

これで、車の静的プロパティは道路上の車輪の数(4)となり、これはすべての車に適用されます。

HTH


1

クラスファイルをロードするのはClassLoaderです。独自のクラスを作成するとどうなるか見てみましょう。

例1:

class StaticTest {

      static int a;
      int b;
      int c;
}

これで、クラス "StaticTest"に3つのフィールドがあることがわかります。しかし、実際には、b、cメンバー変数は存在しません。しかし、なぜですか???。OK参照してください。ここで、b、cはインスタンス変数です。インスタンス変数はオブジェクト作成時にメモリを取得するためです。したがって、ここではb、cはまだメモリを取得していません。そのため、b、cは存在しません。なので、aの存在しかありません。ClassLoaderの場合、aに関する情報は1つだけです。ClassLoaderはまだインスタンス化されていないオブジェクトであるため、b、cを認識しません。

別の例を見てみましょう:例2:

class StaticTest {

      public void display() {
          System.out.println("Static Test");
      }


      public static void main(String []cmd) {

             display();       
      }

}

このコードをコンパイルしようとすると、コンパイラーはCEエラーを出します。CE:非静的メソッドdisplay()は静的コンテキストから参照できません。

ClassLoaderの場合、次のようになります。

class StaticTest {

      public static void main(String []cmd) {

             display();       
      }

}

例2では、​​CEエラーは、静的コンテキストから非静的メソッドを呼び出すためです。そのため、ClassLoaderがコンパイル時にメソッドdisplay()を認識できないため、コンパイル時エラーが発生します。


回答を完了する前に、誤って回答を送信した可能性がありますか?それを編集して不足しているコンテンツを追加してください、ありがとう!
2015

1

インスタンスメソッドまたはインスタンス変数を呼び出す前に、オブジェクト(インスタンス)が必要です。静的メソッドコンパイラーからインスタンス変数が呼び出された場合、コンパイラーは、この変数がどのオブジェクトに属しているかがわかりません。静的メソッドにはオブジェクトがないため(常に1つのコピーのみ)。インスタンス変数またはインスタンスメソッドをインスタンスメソッドから呼び出すと、thisオブジェクトが参照されます。つまり、変数は作成されたオブジェクトに属し、各オブジェクトにはインスタンスメソッドと変数の独自のコピーがあります。

静的変数はとしてマークされstatic、インスタンス変数には特定のキーワードがありません。


0

これは、すべての初心者のための静的キーワードについて説明するのに少し違います。
クラスとオブジェクトをさらに使用すると、それを明確に知ることができます。

| * | Static:静的項目はクラス名で呼び出すことができます
コードで確認すると、一部の関数は次のようなクラス名で直接呼び出されます

NamCls.NamFnc();

System.out.println();

これは、NamFncとprintlnがstaticキーワードを使用して宣言されるためです。

| * | 非静的:非静的項目はクラス変数で呼び出すことができます。
静的でない場合は、クラスの変数が必要 です。
クラス変数の後にドットを付けて、
関数を呼び出します。

NamCls NamObjVar = new NamCls();
NamObjVar.NamFnc();


以下のコードはあなたをきちんと説明しています

| * | クラスの静的および非静的関数:

public class NamCls
{
    public static void main(String[] args)
    {
        PlsPrnFnc("Tst Txt");

        NamCls NamObjVar = new NamCls();
        NamObjVar.PrnFnc("Tst Txt");
    }

    static void PlsPrnFnc(String SrgPsgVal)
    {
        System.out.println(SrgPsgVal);
    }

    void PrnFnc(String SrgPsgVal)
    {
        System.out.println(SrgPsgVal);
    }
}


| * | クラス内の静的および非静的クラス:

public class NamCls
{
    public static void main(String[] args)
    {
        NamTicCls NamTicVaj = new NamTicCls();
        NamTicVaj.PrnFnc("Tst Txt");

        NamCls NamObjVar = new NamCls();
        NamNicCls NamNicVar = NamObjVar.new NamNicCls();
        NamNicVar.PrnFnc("Tst Txt");
    }

    static class NamTicCls
    {
        void PrnFnc(String SrgPsgVal)
        {
            System.out.println(SrgPsgVal);
        }
    }

    class NamNicCls
    {
        void PrnFnc(String SrgPsgVal)
        {
            System.out.println(SrgPsgVal);
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.