Нестатичну змінну не можна посилатись із статичного контексту


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 так, як вона призначена для використання, як об'єктно-орієнтовану мову.
Ерік Г. Хагстром

Відповіді:


294

Ви повинні зрозуміти різницю між класом та екземпляром цього класу. Якщо ви бачите автомобіль на вулиці, ви відразу знаєте, що це машина, навіть якщо ви не бачите, яка модель чи тип. Це тому, що ви порівнюєте побачене з класом "машина". Клас містить те, що схоже на всі автомобілі. Подумайте про це як шаблон чи ідею.

У той же час, автомобіль, який ви бачите, є екземпляром класу "автомобіль", оскільки він має всі властивості, які ви очікуєте: є хтось за кермом, у нього двигун, колеса.

Тож клас каже, що "всі машини мають колір", а примірник каже, що "ця машина є червоною".

У світі 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()).


Я зараз це пояснюю нашому новому колезі - дякую за це чудове пояснення. Це має відповісти на прийняття.
Супахупе

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 командний рядок, наприклад, 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(), і пам’ятайте, що це статичний метод ... Потім ви оголошуєте локальну змінну для цього методу (сравнениеCount, низький, високий і т. Д.). Область застосування цієї змінної є лише заявленим методом, незалежно від того, є він статичним або нестатичним методом. Тому ви не можете використовувати ці змінні за межами цього методу. Це основна помилка 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

3

Я спробую пояснити вам статичну річ. Перш за все статичні змінні не належать до жодного конкретного примірника класу. Їх розпізнають з назвою класу. Статичні методи знову не належать до жодного конкретного випадку. Вони можуть отримати доступ лише до статичних змінних. Уявіть, ви викликаєте MyClass.myMethod (), а myMethod - статичний метод. Якщо ви використовуєте нестатичні змінні всередині методу, то як, пекло на землі, він би знав, які змінні використовувати? Ось чому ви можете використовувати зі статичних методів лише статичні змінні. Ще раз повторюю, вони НЕ належать до якогось конкретного екземпляра.


2
  • Перше - знати різницю між екземпляром класу і самим класом. Клас моделює певні властивості та поведінку цілого в контексті цих властивостей. Екземпляр визначатиме конкретні значення для цих властивостей.

  • Все, що пов'язане зі статичним ключовим словом, доступне в контексті класу, а не в контексті примірника класу

  • Як наслідок вищезазначеного

    1. змінні в межах методу не можуть бути статичними
    2. статичні поля та методи потрібно викликати за допомогою імені класу, наприклад, MyProgram7.main (...)
  • Термін служби статичного поля / методу еквівалентний терміну служби вашої програми

Наприклад, автомобіль має колір властивості та демонструє поведінку "руху". Екземпляром автомобіля буде Червоний Фольксваген в русі на 25 км / год.

Тепер статичною властивістю автомобіля буде кількість коліс (4) на дорозі, і це стосується всіх автомобілів.

HTH


1

Завантажити файли класу відповідає ClassLoader. Подивимося, що відбувається, коли ми пишемо власні класи.

Приклад 1:

class StaticTest {

      static int a;
      int b;
      int c;
}

Тепер ми можемо бачити, що клас "StaticTest" має 3 поля. Але насправді немає змінної b, c члена. Але чому ???. Добре бачимо. Тут b, c є змінною екземпляра. Змінна екземпляра Since отримує пам'ять під час створення об'єкта. Тож ось 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: відображення нестатичного методу () не може посилатися на статичний контекст.

Тепер для 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 будуть оголошені, використовуючи ключові слова статичні перед ними.

| * | Нестатичні: Нестатичні елементи можна викликати змінною класу.
Якщо вона не є статичною, вам потрібна змінна класу,
поставити крапку після змінної класу, а
потім викликати функцію.

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.