"非静态方法无法从静态上下文中引用"背后的原因是什么?

Dra*_*orn 259 java static

非常常见的初学者错误是当您尝试"静态"使用类属性而不创建该类的实例时.它会留下您提到的错误消息:

您可以将非静态方法设为静态,也可以使该类的实例使用其属性.

为什么?我不是要求解决方案.我很高兴知道它背后的原因是什么.核心原因!

private java.util.List<String> someMethod(){
    /* Some Code */
    return someList;            
}

public static void main(String[] strArgs){          
     // The following statement causes the error. You know why..
    java.util.List<String> someList = someMethod();         
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*uch 352

你不能打电话给不存在的东西.由于尚未创建对象,因此尚不存在非静态方法.静态方法(根据定义)始终存在.

  • @Vladimir,好的,如果你想挑剔.:)"在当前上下文中不存在":) (50认同)
  • 方法本身确实存在.在加载的类定义中的某处.所以答案是错的:) (8认同)
  • "由于您尚未创建对象,因此尚未存在非静态方法." - 非常感谢你.我应该想到它. (7认同)
  • "你不能称之为不存在的东西." - 暴徒:p (3认同)
  • `static` 方法无法判断非静态成员属于哪个特定对象。由于不存在现有对象,因此非静态方法不属于任何对象。因此,无法从“静态”上下文中引用非静态方法。 (3认同)

Ste*_*owe 61

您尝试调用的方法是实例级方法; 你没有实例.

static方法属于类,非static方法属于类的实例.

  • @ZiG:因为你告诉它不要将它标记为静态 (9认同)
  • 对于初学者,我创建了一个示例来了解@ StevenA.Lowe上面提到的内容.https://repl.it/repls/WavyNeighboringSpotteddolphin (2认同)

Mic*_*rdt 29

面向对象编程的本质是将逻辑与其操作的数据一起封装.

实例方法是逻辑,实例字段是数据.它们共同构成了一个对象.

public class Foo
{
    private String foo;
    public Foo(String foo){ this.foo = foo; }
    public getFoo(){ return this.foo; }

    public static void main(String[] args){
        System.out.println( getFoo() );
    }
}
Run Code Online (Sandbox Code Playgroud)

运行上述程序的结果可能是什么?

没有对象,就没有实例数据,虽然实例方法作为类定义的一部分存在,但它们需要一个对象实例来为它们提供数据.

理论上,不访问任何实例数据的实例方法可以在静态上下文中工作,但实际上没有任何理由将其作为实例方法.无论如何,这是一个语言设计决定,而不是制定一个额外的规则来禁止它.


Hug*_*ugo 12

我刚刚意识到,我认为人们不应该很早就接触到"静态"的概念.

静态方法应该是例外而不是常态.如果你想学习OOP,尤其是早期.(为什么从规则的例外开始?)这是Java的反教学法,你应该学习的"第一"东西是公共静态无效的主要东西.(很少有真正的Java应用程序有自己的主要方法.)


Eri*_*idt 11

我认为值得指出的是,通过Java语言的规则,Java编译器会插入相当于"this"的内容.当它注意到您在没有显式实例的情况下访问实例方法或实例字段时.当然,编译器知道它只能从具有"this"变量的实例方法中执行此操作,而静态方法则不会.

这意味着当您使用实例方法时,以下内容是等效的:

instanceMethod();
this.instanceMethod();
Run Code Online (Sandbox Code Playgroud)

这些也是等价的:

... = instanceField;
... = this.instanceField;
Run Code Online (Sandbox Code Playgroud)

编译器正在有效地插入"this".当您不提供特定实例时.

编译器的"神奇帮助"这一点(双关语)会使初学者感到困惑:它意味着实例调用和静态调用有时看起来具有相同的语法,而实际上是不同类型和底层机制的调用.

由于支持多态的虚方法的行为,实例方法调用有时被称为方法调用或调度; 无论您是编写要使用的显式对象实例还是编译器插入"this",都会发生调度行为.

静态方法调用机制更简单,就像非OOP语言中的函数调用一样.

就个人而言,我认为错误消息具有误导性,它可能是"非静态方法无法在未指定显式对象实例的情况从静态上下文中引用 ".


编译器抱怨的是它不能简单地插入标准"this".就像在实例方法中一样,因为这段代码在静态方法中; 但是,也许作者只是忘了为这个调用提供感兴趣的实例 - 例如,一个可能作为参数提供给静态方法的实例,或者在这个静态方法中创建的实例.

简而言之,您肯定可以在静态方法中调用实例方法,您只需要为调用指定一个显式实例对象.


And*_*NER 7

到目前为止,答案描述了原因,但这里有一些你可能想要考虑的事情:

您可以通过向其构造函数附加方法调用来从可实例化的类中调用方法,

Object instance = new Constuctor().methodCall();
Run Code Online (Sandbox Code Playgroud)

要么

primitive name = new Constuctor().methodCall();
Run Code Online (Sandbox Code Playgroud)

这很有用,您只希望在单个范围内使用一次可实例化类的方法.如果从单个作用域内的可实例化类调用多个方法,则肯定会创建一个可参考的实例.


Viv*_*ani 5

如果我们尝试从静态上下文访问实例方法,编译器将无法猜测您指的是哪个实例方法(哪个对象的变量)。不过,您始终可以使用对象引用访问它。