初学者最常犯的错误是试图“静态”地使用类属性而不创建该类的实例。它会给你留下上面提到的错误信息:
您可以将非静态方法设置为静态,也可以创建该类的实例来使用它的属性。
背后的原因是什么?我关心的不是解决方法,而是原因。
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();
}
到目前为止,答案描述了原因,但还有一件事你可能需要考虑:
你可以通过将方法调用附加到可实例化类的构造函数来调用方法,
Object instance = new Constuctor().methodCall();
or
primitive name = new Constuctor().methodCall();
如果您只希望在单个作用域内使用一次可实例化类的方法,这是非常有用的。如果在一个作用域中从一个可实例化类调用多个方法,一定要创建一个可引用的实例。
面向对象编程的本质是将逻辑与它所操作的数据封装在一起。
实例方法是逻辑,实例字段是数据。它们一起构成了一个物体。
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() );
}
}
运行上述程序可能会得到什么结果?
没有对象,就没有实例数据,虽然实例方法作为类定义的一部分存在,但它们需要对象实例为它们提供数据。
理论上,不访问任何实例数据的实例方法可以在静态上下文中工作,但实际上没有任何理由将其作为实例方法。这是一种语言设计决定,无论如何都要允许它,而不是制定一个额外的规则来禁止它。
我认为值得指出的是,根据Java语言的规则,当Java编译器注意到您在没有显式实例的情况下访问实例方法或实例字段时,它会插入等价的“this.”。当然,编译器知道它只能在实例方法中执行此操作,该实例方法有一个“this”变量,而静态方法没有。
这意味着当你在一个实例方法中,以下是等价的:
instanceMethod();
this.instanceMethod();
这些也是等价的:
... = instanceField;
... = this.instanceField;
当您没有提供特定实例时,编译器会有效地插入“this.”。
编译器的这种“神奇帮助”(双关语)可能会让新手感到困惑:这意味着实例调用和静态调用有时看起来具有相同的语法,而实际上是不同类型和底层机制的调用。
实例方法调用有时被称为方法调用或分派,因为虚拟方法的行为支持多态;不管你是写了一个显式的对象实例来使用,还是编译器插入了一个"this.",分派行为都会发生。
静态方法调用机制更简单,就像非oop语言中的函数调用一样。
就我个人而言,我认为错误消息是误导性的,它可以读为“在没有指定显式对象实例的情况下,不能从静态上下文中引用非静态方法”。
编译器抱怨的是它不能像在实例方法中那样简单地插入标准的"this.",因为这段代码是在静态方法中;然而,可能作者只是忘记为这个调用提供感兴趣的实例——例如,一个实例可能作为参数提供给静态方法,或者在这个静态方法中创建。
简而言之,您当然可以从静态方法中调用实例方法,您只需要为调用指定一个显式的实例对象。