无法从静态上下文引用非静态变量

时间:2010-04-01 09:57:20

标签: java variables compiler-errors non-static

我写了这个测试代码:

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

如何让我的方法识别我的类变量?

12 个答案:

答案 0 :(得分:254)

您必须了解类和该类实例之间的区别。如果你在街上看到一辆汽车,即使你看不到哪种型号或类型,你也会立即知道它是一辆汽车。这是因为您将所看到的内容与“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())。

答案 1 :(得分:72)

静态字段和方法连接到类本身而不是其实例。如果您有一个班级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
    }
}

答案 2 :(得分:36)

static关键字修改了类中方法或变量的生命周期。在加载类时创建static方法或变量。仅当将类实例化为对象(例如,使用static运算符)时,才会创建未声明为new的方法或变量。

从广义上讲,课程的生命周期是:

  1. 写入类的源代码创建模板或 然后可用于
  2. 的图案或印章
  3. 使用new运算符创建一个对象,使用该类将该类的实例作为实际对象,然后在完成对象时
  4. 在垃圾回收期间销毁回收它所拥有的资源的对象,例如内存。
  5. 为了获得应用程序的初始入口点,Java采用了Java程序必须具有包含具有约定或特殊名称的方法的类的约定。这种特殊方法称为main()。由于该方法必须存在,无论是否已实例化包含main方法的类,因此必须使用main()修饰符声明static方法,以便在加载类时{{1}方法可用。

    结果是,当您通过命令行(例如main())启动Java应用程序时,会发生一系列操作。首先启动并初始化Java虚拟机。接下来,将包含已编译Java代码的helloworld.class文件加载到Java虚拟机中。然后,Java虚拟机在java helloworld类中查找名为helloworld的方法。此方法必须为main(String [] args),以便即使该类实际上未实例化为对象,它也将存在。 Java虚拟机不会通过从类创建对象来创建类的实例。它只是加载类并以static方法开始执行。

    因此,您需要创建类的实例作为对象,然后您可以访问尚未使用main()修饰符声明的类的方法和变量。一旦您的Java程序使用static函数启动,您就可以使用具有main()修饰符的任何变量或方法,因为它们作为要加载的类的一部分存在。

    但是,在将类的实例创建为对象之前,不能使用那些在static方法之外且没有main()修饰符的类的变量和方法在static方法中。创建对象后,您可以使用对象的变量和方法。在编译时,Java编译器会捕获尝试使用没有main()修饰符但没有经过类的对象的类的变量和方法,并将其标记为错误。

    static

答案 3 :(得分:11)

让我们先分析一下你的程序.. 在你的程序中,你的第一个方法是main(),并记住它是静态方法......然后你声明该方法的局部变量(compareCount,low,high等等)。此变量的范围仅是声明的方法,无论它是静态还是非静态方法。所以你不能在那个方法之外使用那些变量。这是你犯的基本错误。

然后我们来到下一点。你告诉静电正在杀了你。 (它可能会杀死你,但它只会给你的程序带来生命!!)首先,你必须了解基本的东西。 *静态方法只调用静态方法,只使用静态变量。 *静态变量或静态方法不依赖于该类的任何实例。 (即如果您更改静态变量的任何状态,它将反映在该类的所有对象中) *因此,您将其称为类变量或类方法。 关于“静态”关键字还有很多。 我希望你现在明白了。首先更改变量的范围并将其声明为静态(以便能够在静态方法中使用它)。

对你的建议是:你误解了变量范围和静态功能的想法。清楚地了解这一点。

答案 4 :(得分:10)

最基本的东西是静态变量或静态方法是在类级别。在实例级方法或变量之前加载类级变量或方法。显然,不能使用未加载的东西。所以java编译器不允许在运行时处理事情在编译时解析。这就是为什么它给你错误非静态的东西不能从静态上下文中引用。您只需要阅读类级别范围,实例级别范围和本地范围。

答案 5 :(得分: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 {
  ...

答案 6 :(得分: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();
  }
}

答案 7 :(得分:4)

我会尝试向你解释静态的东西。首先,静态变量不属于该类的任何特定实例。它们被认可为该类的名称。静态方法再次不属于任何特定实例。他们只能访问静态变量。想象一下,你调用MyClass.myMethod()和myMethod是一个静态方法。如果你在方法中使用非静态变量,地球上究竟会知道使用哪些变量?这就是为什么你只能使用静态方法静态变量。我再说一遍,他们不属于任何特定的实例。

答案 8 :(得分:2)

  • 首先要知道一个类的实例和类本身之间的区别。类对某些属性进行建模,并在这些属性的上下文中对整体的行为进行建模。实例将为这些属性定义特定值。

  • 绑定到static关键字的任何内容都可以在类的上下文中使用,而不是在类的实例的上下文中使用

  • 作为上述

    的必然结果
    1. 方法中的变量不能是静态的
    2. 静态字段,必须使用类名调用方法,例如MyProgram7.main(...)
  • 静态字段/方法的生命周期等同于应用程序的生命周期

E.g。 比方说,汽车具有属性颜色,并表现出行为'运动'。 汽车的一个例子是红色大众甲壳虫以25公里/小时的速度运动。

现在汽车的静态属性是道路上的轮子(4)的数量,这适用于所有汽车。

HTH

答案 9 :(得分:2)

在调用实例方法或实例变量之前它需要一个对象(Instance)。当从静态方法调用实例变量时,编译器不知道该变量属于哪个对象。因为静态方法没有对象(总是只有一个副本)。从实例方法调用实例变量或实例方法时,它会引用this对象。这意味着变量属于创建的任何对象,每个对象都有自己的实例方法和变量副本。

静态变量标记为static,实例变量没有特定的关键字。

答案 10 :(得分:1)

对于所有初学者来说,这是一个有点不同的解释静态关键词 当您使用Classes和Objects更多地工作时,您将清楚地了解它。

| * | 静态:可以使用类名称来调用静态项目 如果您在代码中观察到,某些函数会直接使用类名称来调用,如

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

答案 11 :(得分:0)

负责加载类文件的是ClassLoader。让我们看看编写自己的类时会发生什么。

示例1:

class StaticTest {

      static int a;
      int b;
      int c;
}

现在我们可以看到那个&#34; StaticTest&#34;有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()。因此发生编译时错误。