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

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

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

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

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

静态方法属于类,非静态方法属于类的实例。


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


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

Ex:

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


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

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


到目前为止,答案描述了原因,但还有一件事你可能需要考虑:

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

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

or

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

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


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

静态方法应该是例外,而不是规范。尤其是在你想学习OOP的时候。(为什么要从规则的例外开始呢?)这与Java的教学方法截然相反,你应该学习的“第一件”事情是公共静态空的主要内容。(很少有真正的Java应用程序有自己的主方法。)


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


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

实例方法是逻辑,实例字段是数据。它们一起构成了一个物体。

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.",因为这段代码是在静态方法中;然而,可能作者只是忘记为这个调用提供感兴趣的实例——例如,一个实例可能作为参数提供给静态方法,或者在这个静态方法中创建。

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


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


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

Well, since you are developing in Java, the compiler generates an object code that the Java Virtual Machine can interpret. The JVM anyway is a binary program that run in machine language (probably the JVM’s version specific for your operating system and hardware was previously compiled by another programming language like C in order to get a machine code that can run in your processor). At the end, any code is translated to machine code. So, create an object (an instance of a class) is equivalent to reserve a memory space (memory registers that will be processor registers when the CPU scheduler of the operating system put your program at the top of the queue in order to execute it) to have a data storage place that can be able to read and write data. If you don’t have an instance of a class (which happens on a static context), then you don’t have that memory space to read or write the data. In fact, like other people had said, the data don’t exist (because from the begin you never had written neither had reserved the memory space to store it).

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


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

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