初学者最常犯的错误是试图“静态”地使用类属性而不创建该类的实例。它会给你留下上面提到的错误信息:

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

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

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语言的规则,当Java编译器注意到您在没有显式实例的情况下访问实例方法或实例字段时,它会插入等价的“this.”。当然,编译器知道它只能在实例方法中执行此操作,该实例方法有一个“this”变量,而静态方法没有。

这意味着当你在一个实例方法中,以下是等价的:

instanceMethod();
this.instanceMethod();

这些也是等价的:

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

当您没有提供特定实例时,编译器会有效地插入“this.”。

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

实例方法调用有时被称为方法调用或分派,因为虚拟方法的行为支持多态;不管你是写了一个显式的对象实例来使用,还是编译器插入了一个"this.",分派行为都会发生。

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

就我个人而言,我认为错误消息是误导性的,它可以读为“在没有指定显式对象实例的情况下,不能从静态上下文中引用非静态方法”。


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

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

其他回答

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

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

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

这意味着当你在一个实例方法中,以下是等价的:

instanceMethod();
this.instanceMethod();

这些也是等价的:

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

当您没有提供特定实例时,编译器会有效地插入“this.”。

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

实例方法调用有时被称为方法调用或分派,因为虚拟方法的行为支持多态;不管你是写了一个显式的对象实例来使用,还是编译器插入了一个"this.",分派行为都会发生。

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

就我个人而言,我认为错误消息是误导性的,它可以读为“在没有指定显式对象实例的情况下,不能从静态上下文中引用非静态方法”。


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

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

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

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

编译器实际上为非静态方法添加了一个参数。它添加了一个this指针/引用。这也是为什么静态方法不能使用这个的原因,因为没有对象。