정적이 아닌 변수는 정적 컨텍스트에서 참조 할 수 없습니다


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);
                           ^

클래스 변수를 인식하는 메소드를 얻으려면 어떻게해야합니까?


가능할 때마다 정적을 사용하지 마십시오. 에서처럼 전체 정적 프로그램을 작성할 수 있습니다C . 그러나 그것은 좋은 것이 아닙니다. Java를 객체 지향 언어로 사용되는 방식으로 사용하십시오.
Erick G. Hagstrom

답변:


294

클래스와 해당 클래스의 인스턴스의 차이점을 이해해야합니다. 길거리에서 자동차를 보면 어떤 모델이나 유형을 볼 수 없어도 자동차라는 것을 즉시 알 수 있습니다. 이것은 당신이 보는 것을 클래스 "car" 와 비교하기 때문 입니다. 이 클래스에는 모든 자동차와 비슷한 것이 포함되어 있습니다. 템플릿이나 아이디어로 생각하십시오.

동시에, 당신이 보는 자동차는 당신이 기대하는 모든 속성을 가지고 있기 때문에 "car"클래스의 인스턴스입니다 : 그것을 운전하는 누군가가 있고, 엔진, 바퀴가 있습니다.

따라서 클래스는 "모든 자동차는 색상을가집니다"라고 말하고 인스턴스는 "이 특정 자동차는 빨간색입니다"를 말합니다.

OO 세계에서는 클래스를 정의하고 클래스 내부에서 유형 필드를 정의합니다 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 Virtual Machine이 시작되고 초기화됩니다. 다음으로 컴파일 된 Java 코드가 포함 된 helloworld.class 파일이 Java Virtual Machine에로드됩니다. 그런 다음 Java Virtual Machine은 helloworld클래스 에서라는 메소드를 찾습니다 main(String [] args). 이 메소드는 static클래스가 실제로 객체로 인스턴스화되지 않은 경우에도 존재하도록 해야 합니다. Java Virtual Machine은 클래스에서 객체를 만들어 클래스의 인스턴스를 만들지 않습니다. 그냥 클래스를로드하고 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 등)를 선언하십시오. 이 변수의 범위는 정적 또는 비 정적 메소드에 관계없이 선언 된 메소드입니다. 따라서 해당 메소드 외부에서 해당 변수를 사용할 수 없습니다. 이것이 기본 오류입니다.

다음으로 넘어갑니다. 당신은 정적이 당신을 죽이고 있다고 말했다. (당신을 죽일 수도 있지만 프로그램에 생명을 줄뿐입니다!) 먼저 기본 사항을 이해해야합니다. * 정적 메소드는 정적 메소드 만 호출하고 정적 변수 만 사용하십시오. * 정적 변수 또는 정적 메소드는 해당 클래스의 인스턴스에 종속되지 않습니다. (즉, 정적 변수의 상태를 변경하면 클래스의 모든 객체에 반영됩니다) *이 때문에 클래스 변수 또는 클래스 메소드로 호출합니다. 그리고 "정적"키워드에 대해 더 많은 것이 있습니다. 나는 이제 당신이 아이디어를 얻길 바랍니다. 먼저 변수의 범위를 변경하고 정적로 선언하십시오 (정적 메소드에서 사용할 수 있도록).

그리고 당신을위한 충고는 : 당신은 변수와 정적 기능의 범위에 대한 아이디어를 오해했습니다. 그것에 대해 분명한 아이디어를 얻으십시오.


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

3

나는 당신에게 정적 인 것을 설명하려고 노력할 것입니다. 먼저 모든 정적 변수는 클래스의 특정 인스턴스에 속하지 않습니다. 그들은 클래스의 이름으로 인식됩니다. 정적 메소드는 다시 특정 인스턴스에 속하지 않습니다. 정적 변수에만 액세스 할 수 있습니다. MyClass.myMethod ()를 호출한다고 가정하면 myMethod는 정적 메소드입니다. 메소드 내에서 정적이 아닌 변수를 사용하면 지구상의 지옥은 어떤 변수를 사용할지 어떻게 알 수 있습니까? 그래서 정적 메소드에서만 정적 변수를 사용할 수 있습니다. 나는 특정 인스턴스에 속하지 않는 것을 반복한다.


2
  • 첫 번째는 클래스의 인스턴스와 클래스 자체의 차이점을 아는 것입니다. 클래스는 특정 속성과 해당 속성의 맥락에서 전체의 동작을 모델링합니다. 인스턴스는 해당 속성에 대한 특정 값을 정의합니다.

  • 정적 키워드에 바인딩 된 것은 클래스 인스턴스의 컨텍스트가 아닌 클래스의 컨텍스트에서 사용할 수 있습니다

  • 위의 결과로

    1. 메소드 내의 변수는 정적 일 수 없습니다
    2. 정적 필드 및 메소드는 클래스 이름을 사용하여 호출해야합니다. 예 : MyProgram7.main (...)
  • 정적 필드 / 방법의 수명은 응용 프로그램의 수명과 같습니다.

예를 들어, 자동차는 속성 색상을 가지며 '모션'동작을 나타냅니다. 자동차의 예는 25kmph에서 움직이는 붉은 폭스 바겐 비틀입니다.

이제 자동차의 정적 속성은 도로의 바퀴 수 (4)가 될 것이며, 이는 모든 자동차에 적용됩니다.

HTH


1

클래스 파일을로드하는 것은 ClassLoader의 책임입니다. 클래스를 작성할 때 어떤 일이 발생하는지 봅시다.

예 1 :

class StaticTest {

      static int a;
      int b;
      int c;
}

이제 "StaticTest"클래스에 3 개의 필드가 있음을 알 수 있지만 실제로 b, c 멤버 변수는 없습니다. 그러나 왜 ???. 알았어요. 여기서 b, c는 인스턴스 변수입니다. 인스턴스 변수는 객체 생성시 메모리를 가져옵니다. 그래서 여기 b, c는 아직 메모리를 얻지 못했습니다. 그것이 b, c의 존재가없는 이유입니다. 그래서 오직 존재합니다. ClassLoader의 경우 a에 대한 정보가 하나만 있습니다. 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 () 메소드를 인식 할 수 없으므로 컴파일 시간 오류가 발생합니다.


답변을 마치기 전에 실수로 답변을 제출했을까요? 편집하고 누락 된 내용을 추가하십시오 (감사합니다).
plamut

1

인스턴스 메소드 또는 인스턴스 변수를 호출하기 전에 오브젝트 (인스턴스)가 필요합니다. 정적 메소드 컴파일러에서 인스턴스 변수가 호출되면이 변수가 속한 객체를 알 수 없습니다. 정적 메소드에는 객체가 없기 때문에 (한 사본 만 항상). 인스턴스 메소드에서 인스턴스 변수 또는 인스턴스 메소드를 호출하면 this오브젝트를 참조 합니다. 변수는 생성 된 객체에 속하며 각 객체에는 고유 한 인스턴스 메소드 및 변수 사본이 있습니다.

정적 변수는로 표시되며 static인스턴스 변수에는 특정 키워드가 없습니다.


0

이것은 모든 초보자를위한 정적 키워드에 대해 설명하기에는 약간 다릅니다.
클래스와 객체로 더 많은 작업을 할 때 명확하게 알 수 있습니다.

| * | 정적 : 클래스 이름으로 정적 항목 호출 가능
코드에서 관찰하면 일부 함수는 클래스 이름으로 직접 호출됩니다.

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.