什么是“不能从静态上下文引用非静态方法”背后的原因?

4si2a6ki  于 2021-06-29  发布在  Java
关注(0)|答案(13)|浏览(430)

这个问题在这里已经有答案了

不能从静态上下文引用非静态变量(12个答案)
6年前关门了。
初学者最常犯的错误是,试图“静态地”使用一个类属性而不创建该类的示例。它会给您留下所提到的错误消息:
可以使非静态方法成为静态的,也可以使该类的示例使用其属性。
为什么?我不是在寻求解决办法。我很想知道这背后的原因是什么。最核心的原因!

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

b1zrtrql1#

如果一个方法不是静态的,它“告诉”编译器该方法需要访问类中的示例级数据(如非静态字段)。除非已创建类的示例,否则此数据将不可用。因此,如果您试图从静态方法调用该方法,编译器将抛出一个错误。。如果该方法实际上没有引用类的任何非静态成员,则使该方法成为静态的。
例如,在resharper中,只要创建一个不引用类的任何静态成员的非静态方法,就会生成一条警告消息“thismethodcanbeastatic”

xeufq47z

xeufq47z2#

静态方法将动作与对象类型相关联,而非静态方法将动作与对象类型的示例相关联。通常,它是一个方法,它执行与示例相关的操作。
前任:
类车可能有一个wash方法,它将指示清洗特定的车,而静态方法将应用于类型车。

wbgh16ku

wbgh16ku3#

非静态方法依赖于对象。一旦对象被创建,程序就会识别它。
静态方法甚至可以在创建对象之前调用。静态方法非常适合进行不依赖于您计划使用的实际对象的比较或操作。

mdfafbf1

mdfafbf14#

您试图调用的方法是示例级方法;您没有示例。 static 方法属于类,非- static 方法属于类的示例。

axr492tv

axr492tv5#

我刚刚意识到,我认为人们不应该很早就接触到“静态”的概念。
静态方法应该是例外而不是规范。如果你想学oop的话,尤其是在早期(为什么要从一个例外的规则开始呢?)这与java的教学法是背道而驰的,您应该学习的“第一件”事情是最主要的事情(很少有真正的java应用程序有自己的主方法。)

cwdobuhd

cwdobuhd6#

到目前为止,答案描述了原因,但您可能还需要考虑以下问题:
通过将方法调用附加到构造函数中,可以从可示例化类调用方法,

Object instance = new Constuctor().methodCall();

primitive name = new Constuctor().methodCall();

如果您只希望在一个范围内使用一次可示例化类的方法,这将非常有用。如果要从单个作用域中的一个可示例类调用多个方法,那么一定要创建一个可引用示例。

pftdvrlh

pftdvrlh7#

面向对象编程的本质是将逻辑与它所操作的数据封装在一起。
示例方法是逻辑,示例字段是数据。它们一起形成一个物体。

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

运行上述程序的结果可能是什么?
没有对象,就没有示例数据,虽然示例方法作为类定义的一部分存在,但它们需要一个对象示例为它们提供数据。
从理论上讲,不访问任何示例数据的示例方法可以在静态上下文中工作,但实际上没有任何理由将其作为示例方法。这是一个语言设计的决定,允许它无论如何,而不是制定一个额外的规则来禁止它。

yhxst69z

yhxst69z8#

我认为值得指出的是,根据java语言的规则,当java编译器注意到您正在访问没有显式示例的示例方法或示例字段时,它会插入等价的“this”。当然,编译器知道它只能在示例方法中执行此操作,而示例方法有一个“this”变量,而静态方法没有。
这意味着当您使用示例方法时,以下是等效的:

instanceMethod();
this.instanceMethod();

这些也是等价的:

... = instanceField;
... = this.instanceField;

当您不提供特定的示例时,编译器有效地插入了“this.”。
编译器的这一点(双关语)的“神奇帮助”可能会让新手感到困惑:这意味着示例调用和静态调用有时看起来具有相同的语法,而实际上是不同类型和底层机制的调用。
示例方法调用有时被称为方法调用或分派,因为支持多态性的虚拟方法的行为;无论是编写要使用的显式对象示例还是编译器插入了“this”,都会发生分派行为。
静态方法调用机制更简单,就像非oop语言中的函数调用一样。
就我个人而言,我认为错误消息是误导性的,它可能会读为“非静态方法不能从静态上下文中引用,而不指定显式对象示例”。
编译器抱怨的是,它不能像在示例方法中那样简单地插入标准“this”,因为这段代码在静态方法中;然而,可能作者只是忘记了为这个调用提供感兴趣的示例——比如说,一个示例可能作为参数提供给静态方法,或者在这个静态方法中创建。
简而言之,您完全可以从静态方法中调用示例方法,您只需要拥有并指定一个显式的示例对象来进行调用。

btqmn9zl

btqmn9zl9#

你不能叫不存在的东西。因为还没有创建对象,所以非静态方法还不存在。静态方法(根据定义)总是存在的。

niknxzdl

niknxzdl10#

所以你问的是一个非常核心的原因?
因为您是用java开发的,所以编译器会生成一个java虚拟机可以解释的目标代码。无论如何,jvm是一个以机器语言运行的二进制程序(可能jvm特定于您的操作系统和硬件的版本以前是由另一种编程语言(如c)编译的,以便获得可以在处理器中运行的机器代码)。最后,任何代码都被翻译成机器代码。因此,创建一个对象(类的一个示例)相当于保留一个内存空间(当操作系统的cpu调度器将您的程序放在队列的顶部以便执行它时,内存寄存器将成为处理器寄存器),以便有一个能够读写数据的数据存储位置。如果没有类的示例(发生在静态上下文中),那么就没有足够的内存空间来读取或写入数据。事实上,正如其他人所说,数据并不存在(因为从一开始你就没有写过,也没有预留存储空间)。
对不起我的英语!我是拉丁人!

rnmwe5a2

rnmwe5a211#

这背后的原因很简单,父类的静态数据成员可以被访问(仅当它们没有被重写时),但例如(非静态)数据成员或方法,我们需要它们的引用,因此只能通过对象调用它们。

uubf1zoe

uubf1zoe12#

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

bvpmtnay

bvpmtnay13#

编译器实际上向非静态方法添加了一个参数。它增加了 this pointer/reference. This is also the reason why a static method can not use this ,因为没有对象。

相关问题