【问题标题】:What is the reason behind "non-static method cannot be referenced from a static context"? [duplicate]“无法从静态上下文中引用非静态方法”背后的原因是什么? [复制]
【发布时间】:2022-12-12 08:08:44
【问题描述】:

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

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

这背后的原因是什么?我不关心解决方案,而是原因。

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

public static void main(String[] strArgs){          
     // The following statement causes the error. 
    java.util.List<String> someList = someMethod();         
}

【问题讨论】:

    标签: java static


    【解决方案1】:

    你不能调用不存在的东西。由于您尚未创建对象,因此非静态方法尚不存在。静态方法(根据定义)始终存在。

    【讨论】:

    • 方法本身确实存在。加载的类定义中的某处。所以答案是错误的:)
    • @Vladimir,好吧,如果你想挑剔的话。 :)“在当前上下文中不存在”:)
    • “你不能调用不存在的东西。” - 暴徒:p
    • static 方法无法判断非静态成员属于哪个特定对象。由于不存在对象,非静态方法不属于任何对象。因此,无法从 static 上下文中引用非静态方法。
    • 完美而简单的答案。惊人的。
    【解决方案2】:

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

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

    【讨论】:

    • “非静态方法属于类的实例”——答案。但是为什么它属于类的实例呢?谢谢你。
    • @ZiG:因为您通过不将其标记为静态来告诉它
    • 对于初学者开发人员,我创建了一个示例来理解 @StevenA.Lowe 上面提到的内容。 repl.it/repls/WavyNeighboringSpotteddolphin
    【解决方案3】:

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

    实例方法是逻辑,实例字段是数据。它们一起形成一个对象。

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

    运行上述程序可能会产生什么结果?

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

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

    【讨论】:

    • “这是一个语言设计决定”这个。
    【解决方案4】:

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

    静态方法可能应该是例外而不是常态。如果您想学习 OOP,尤其是在早期。 (为什么要从规则的例外开始?)这是非常违反 Java 教学法的,您应该学习的“第一”事情是公共静止的无效主要的东西。 (无论如何,很少有真正的 Java 应用程序有自己的主要方法。)

    【讨论】:

    • 我遇到了上述错误的问题,但必须学习如何使用静态才能在不同的活动中使用一个类的实例,所以我一直在努力解决这个问题。 :( 尝试了很多东西,但没有用。
    【解决方案5】:

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

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

    instanceMethod();
    this.instanceMethod();
    

    这些也是等价的:

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

    编译器有效地插入了“this”。当您不提供特定实例时。

    编译器的这种(双关语)“魔法帮助”可能会让新手感到困惑:这意味着实例调用和静态调用有时看起来具有相同的语法,而实际上是不同类型和底层机制的调用。

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

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

    就我个人而言,我认为该错误消息具有误导性,它可能显示为“无法从静态上下文中引用非静态方法无需指定显式对象实例”。


    编译器抱怨的是它不能简单地插入标准的“this”。就像它在实例方法中所做的那样,因为此代码在静态方法中;然而,也许作者只是忘记了为这个调用提供感兴趣的实例——比如说,一个可能作为参数提供给静态方法的实例,或者在这个静态方法中创建的实例。

    简而言之,您当然可以从静态方法中调用实例方法,您只需要为调用指定一个显式实例对象即可。

    【讨论】:

      【解决方案6】:

      到目前为止的答案描述了原因,但您可能还需要考虑以下事项:

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

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

      或者

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

      如果您只想在单个范围内使用一次可实例化类的方法,这很有用。如果您在单个范围内从一个可实例化类调用多个方法,一定要创建一个可引用实例。

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          【解决方案8】:

          静态方法将动作与一种对象类型相关联,而非静态方法将动作与该类型对象的实例相关联。通常,它是一种与实例相关的方法。

          前任:

          Car 类可能有一个 wash 方法,表示清洗特定的汽车,而静态方法将应用于 car 类型。

          【讨论】:

          • 不是所有的方法都有副作用!不必是一个动作,它也可能是对象告诉你的东西。
          【解决方案9】:

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

          例如,在 Resharper 中,仅创建一个不引用类的任何静态成员的非静态方法会生成一条警告消息“此方法可以设为静态”

          【讨论】:

            【解决方案10】:

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

            【讨论】:

              【解决方案11】:

              所以你问的是一个非常核心的原因?

              好吧,因为你是用 Java 开发的,所以编译器会生成一个 Java 虚拟机可以解释的目标代码。 JVM 无论如何是一个以机器语言运行的二进制程序(可能 JVM 的特定于您的操作系统和硬件的版本之前由另一种编程语言(如 C)编译以获得可以在您的处理器中运行的机器代码)。最后,任何代码都被翻译成机器代码。所以,创建一个对象(一个类的实例)就相当于预留了一块内存空间(当操作系统的CPU调度器把你的程序排在队首以便执行时,内存寄存器就是处理器寄存器)有一个可以读取和写入数据的数据存储位置。如果您没有类的实例(发生在静态上下文中),那么您就没有内存空间来读取或写入数据。事实上,正如其他人所说,数据不存在(因为从一开始你就没有写过,也没有预留内存空间来存储它)。

              对不起我的英语不好!我是拉丁人!

              【讨论】:

              • 是的,但是您执行 main() 类的事实证明已分配内存并且操作系统正在读取和写入您的代码。
              【解决方案12】:

              这背后的简单原因是父类的静态数据成员 可以访问(仅当它们未被覆盖时)但例如(非静态) 数据成员或方法我们需要他们的参考,所以他们只能是 通过对象调用。

              【讨论】:

                【解决方案13】:

                非静态方法依赖于对象。一旦创建了对象,程序就会识别它。

                甚至可以在创建对象之前调用静态方法。静态方法非常适合进行不依赖于您计划使用的实际对象的比较或操作。

                【讨论】:

                  猜你喜欢
                  • 2010-09-22
                  • 2011-05-17
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多