На нестатическую переменную нельзя ссылаться из статического контекста


290

Я написал этот тестовый код:

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 так, как он предназначен для использования в качестве объектно-ориентированного языка.
Эрик Дж. Хагстром

Ответы:


294

Вы должны понимать разницу между классом и экземпляром этого класса. Если вы видите автомобиль на улице, вы сразу же знаете, что это автомобиль, даже если вы не видите, какую модель или тип. Это потому, что вы сравниваете то, что видите, с классом «машина». Класс содержит который похож на все автомобили. Думайте об этом как шаблон или идея.

В то же время, автомобиль, который вы видите, является экземпляром класса «автомобиль», поскольку он обладает всеми ожидаемыми свойствами: кто-то за рулем, у него есть двигатель, колеса.

Таким образом, класс говорит, что «все автомобили имеют цвет», а экземпляр говорит, что «этот конкретный автомобиль красный».

В ОО-мире вы определяете класс, а внутри класса вы определяете поле типа 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()).


Я сейчас объясняю это нашему новому коллеге - спасибо за это замечательное объяснение. Это должен принять ответ.
Супахупе

84

Статические поля и методы связаны с самим классом, а не с его экземплярами. Если у вас есть класс 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
    }
}

55

staticКлючевое слово изменяет жизненный цикл метода или переменной в классе. staticМетод или переменная создается во время загружен класс. Метод или переменная, которая не объявлена ​​как static, создается, только когда экземпляр класса создается как объект, например, с помощью newоператора.

Жизненный цикл класса в широком смысле:

  1. исходный код для класса написан с созданием шаблона или шаблона или штампа, который затем может быть использован для
  2. создать объект с newоператором, используя класс, чтобы сделать экземпляр класса в качестве фактического объекта, а затем, когда это будет сделано с объектом
  3. уничтожить объект, освободив ресурсы, которые он содержит, такие как память, во время сборки мусора.

Чтобы иметь начальную точку входа для приложения, Java приняла соглашение, что программа Java должна иметь класс, который содержит метод с согласованным или специальным именем. Этот специальный метод называется main(). Поскольку метод должен существовать независимо от того, был ли создан экземпляр класса, содержащего метод main, main()метод должен быть объявлен с staticмодификатором, чтобы, как только класс был загружен, main()метод был доступен.

В результате, когда вы запускаете ваше Java-приложение из командной строки, например, java helloworldпроисходит ряд действий. Прежде всего, виртуальная машина Java запускается и инициализируется. Затем файл helloworld.class, содержащий скомпилированный код Java, загружается в виртуальную машину 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 и т. Д.). Область действия этой переменной - только объявленный метод, независимо от того, является ли он статическим или нестатическим методом. Таким образом, вы не можете использовать эти переменные вне этого метода. Это основная ошибка, которую вы сделали.

Тогда мы подходим к следующему пункту. Вы сказали, что static убивает вас. (Это может убить вас, но это только оживит вашу программу !!) Сначала вы должны понять основную вещь. * Статический метод вызывает только статический метод и использует только статическую переменную. * Статическая переменная или статический метод не зависят ни от одного экземпляра этого класса. (т.е. если вы измените какое-либо состояние статической переменной, оно будет отражаться во всех объектах класса). * Из-за этого вы называете его как переменную класса или метод класса. И еще много о ключевом слове "static". Я надеюсь, теперь вы поняли идею. Сначала измените область действия переменной и объявите ее как статическую (чтобы иметь возможность использовать ее в статических методах).

И совет для вас: вы неправильно поняли идею области действия переменных и статических функций. Получить четкое представление об этом.


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 (...)
  • Время жизни статического поля / метода эквивалентно времени жизни вашего приложения

Например, автомобиль имеет цвет свойства и демонстрирует поведение «движение». Экземпляр этого автомобиля - красный Volkswagen Beetle, движущийся со скоростью 25 км / ч.

Теперь статическим свойством автомобиля будет количество колес (4) на дороге, и это будет применяться ко всем автомобилям.

НТН


1

ClassLoader отвечает за загрузку файлов классов. Давайте посмотрим, что происходит, когда мы пишем свои собственные классы.

Пример 1:

class StaticTest {

      static int a;
      int b;
      int c;
}

Теперь мы можем видеть, что класс «StaticTest» имеет 3 поля. Но на самом деле не существует переменной-члена b, c. Но почему ???. ОК, дабы увидеть. Здесь b, c - переменная экземпляра. Поскольку переменная экземпляра получает память во время создания объекта. Так что здесь b, c еще не получают никакой памяти. Вот почему не существует б, в. Так что существует только существование. Для ClassLoader у него есть только одна информация о. 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 () во время компиляции. Так что произошла ошибка времени компиляции.


Вероятно, представил ваш ответ случайно, прежде чем вам удалось закончить его? Пожалуйста, отредактируйте его и добавьте недостающий контент, спасибо!
Пламут

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);
        }
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.