“非静态方法不能从静态上下文中引用”背后的原因是什么?
非常常见的初学者错误是,当你尝试使用一个类属性“静态”而没有创build该类的一个实例。 它留下你提到的错误信息。
您可以使非静态方法静态或使该类的实例使用其属性。
为什么? 我不是要求解决scheme。 我将不胜感激,知道背后的原因。 非常核心的原因!
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(); }
你不能调用不存在的东西。 由于您尚未创build对象,因此非静态方法尚不存在。 静态方法(按定义)总是存在的。
您尝试调用的方法是实例级别的方法; 你没有一个实例。
static
方法属于类,非static
方法属于类的实例。
面向对象编程的本质是将逻辑与其操作的数据一起封装起来。
实例方法是逻辑,实例字段是数据。 它们一起构成一个对象。
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() ); } }
运行上述程序的结果可能是什么?
如果没有对象,就没有实例数据,而实例方法作为类定义的一部分存在,它们需要一个对象实例来为它们提供数据。
理论上,一个不访问任何实例数据的实例方法可以在静态上下文中工作,但是实际上没有任何理由将它作为实例方法。 这是一个语言devise决定,无论如何都要允许它,而不是制定一个额外的规则来禁止它。
我刚刚意识到,我认为人们不应该很早就接触到“静态”的概念。
静态方法可能应该是例外而不是规范。 特别是如果你想学习面向对象的早期反正。 (为什么要从规则的例外开始?)这是非常反Java的教育,你应该学习的第一件事是公共静态无效的主要事情。 (很less有真正的Java应用程序有自己的主要方法。)
我认为值得指出的是,通过Java语言的规则,Java编译器插入了“this”的等价物。 当它发现你正在访问的实例方法或实例字段没有明确的实例。 当然,编译器知道它只能在一个有“this”variables的实例方法中做,因为静态方法不行。
这意味着当你在一个实例方法中时,以下是等价的:
instanceMethod(); this.instanceMethod();
这些也是等价的:
... = instanceField; ... = this.instanceField;
编译器正在有效地插入“this”。 当你不提供一个特定的实例。
这个(双关语)编译器的“魔术帮助”可以混淆新手:这意味着实例调用和静态调用有时似乎具有相同的语法,而实际上是不同types和底层机制的调用。
实例方法调用有时被称为方法调用或调度,因为支持多态的虚拟方法的行为; 无论您是使用显式对象实例还是编译器插入“this”,调度行为都会发生。
静态方法调用机制比较简单,就像非OOP语言中的函数调用一样。
就我个人而言,我认为这个错误信息有误导性,它可能会读取“非静态方法不能从静态上下文中引用而不指定显式对象实例 ”
到目前为止的答案描述了为什么,但这是一个你可能要考虑的其他事情:
您可以通过将方法调用附加到其构造函数来调用可实例化类的方法,
Object instance = new Constuctor().methodCall();
要么
primitive name = new Constuctor().methodCall();
这是有用的,你只希望在一个范围内使用一个可实例化类的方法。 如果您在一个范围内从一个可实例化的类调用多个方法,那么一定要创build一个可参照的实例。
编译器实际上为非静态方法添加了一个参数。 它添加了一个this pointer/reference. This is also the reason why a static method can not use this
this pointer/reference. This is also the reason why a static method can not use this
,因为没有对象。
静态方法将一个动作与一个对象types联系起来,而非静态方法将一个动作与该types对象的一个实例联系起来。 通常情况下,这是一种与实例相关的方法。
例如:
class车可能有清洗方法,这将表明清洗一辆特定的汽车,而静态方法将适用于types车。
如果某个方法不是静态的,则“告诉”编译器该方法需要访问类中的实例级数据(如非静态字段)。 除非已创build类的实例,否则此数据将不可用。 因此,如果您尝试从静态方法调用该方法,则编译器会引发错误。如果实际上该方法不引用该类的任何非静态成员,请将该方法设置为静态。
例如,在Resharper中,只是创build一个不引用该类的静态成员的非静态方法会生成一条警告消息“该方法可以变成静态的”
如果我们试图从一个静态的上下文访问一个实例方法,那么编译器就没有办法猜测你所指的是哪个实例方法(哪个对象的variables)。 尽pipe如此,您始终可以使用对象引用来访问它。
其原因很简单,就是父类的静态数据成员可以被访问(只有当它们没有被覆盖时),但是对于实例(非静态)的数据成员或者方法,我们需要它们的引用,所以它们只能通过一个对象。
所以你要求一个非常核心的原因?
那么,因为你正在用Java开发,所以编译器会生成一个Java虚拟机可以解释的对象代码。 无论如何,JVM是以机器语言运行的二进制程序(可能是针对您的操作系统和硬件的JVM版本,之前由另一种编程语言(如C)编译以获得可在处理器中运行的机器代码)。 最后,任何代码都被转换成机器码。 因此,创build一个对象(一个类的实例)相当于保留一个内存空间(当操作系统的CPU调度程序将您的程序放在队列顶部以便执行时,内存寄存器将成为处理器寄存器)有一个可以读写数据的数据存储位置。 如果你没有一个类的实例(这发生在一个静态的上下文中),那么你没有那个内存空间来读或写数据。 事实上,和其他人一样,数据是不存在的(因为从一开始你从未写过既没有保留内存空间来存储它)。
对不起我的英语不好! 我拉丁!
一个非静态方法依赖于对象。 一旦对象被创build,它就被程序所识别。
甚至可以在创build对象之前调用静态方法。 静态方法非常适合于比较或操作,这些比较或操作不依赖于您计划使用的实际对象。