具体来说,我正在尝试以下代码:

package hello;

public class Hello {

    Clock clock = new Clock();

    public static void main(String args[]) {
        clock.sayTime();
    }
}

但是它给出了错误

不能访问静态方法主中的非静态字段

所以我把时钟的声明改为这样:

static Clock clock = new Clock();

这招奏效了。将该关键字放在声明之前意味着什么?它究竟会做什么和/或限制可以对该对象做什么?


当前回答

这里有一个问题是关于这个概念中“静态”一词的选择。这个问题已经解决了,但我认为词源问题还没有明确解决。所以…


这是由于关键字重用,从C开始。

考虑C语言中的数据声明(在函数体中):

    void f() {
        int foo = 1;
        static int bar = 2;
         :
    }

变量foo在输入函数时在堆栈上创建(并在函数终止时销毁)。相比之下,bar总是在那里,所以在普通英语中它是“静态的”——它不会去任何地方。

Java和类似的语言对数据有相同的概念。数据可以为类的每个实例(每个对象)分配,也可以为整个类分配一次。因为Java的目标是为C/ c++程序员提供熟悉的语法,所以这里使用“static”关键字是合适的。

    class C {
        int foo = 1;
        static int bar = 2;
         :
    }

最后,我们来谈谈方法。

    class C {
        int foo() { ... }
        static int bar() { ... }
         :
    }

从概念上讲,类c的每个实例都有一个foo()实例,整个类c只有一个bar()实例。这与我们讨论的数据的情况类似,因此使用'static'也是一个明智的选择,特别是如果你不想在你的语言中添加更多保留的关键字。

其他回答

Static使时钟成员成为类成员而不是实例成员。如果没有static关键字,你需要创建一个Hello类的实例(它有一个时钟成员变量)。

Hello hello = new Hello();
hello.clock.sayTime();

静态成员属于类,而不是特定的实例。

这意味着静态字段只有一个实例存在[1],即使您创建了一百万个类实例,或者您没有创建任何实例。它将被所有实例共享。

因为静态方法也不属于特定的实例,所以它们不能引用实例成员。在给出的示例中,main不知道应该引用Hello类的哪个实例(因此也不知道应该引用Clock类的哪个实例)。静态成员只能引用静态成员。当然,实例成员可以访问静态成员。

旁注:当然,静态成员可以通过对象引用访问实例成员。

例子:

public class Example {
    private static boolean staticField;
    private boolean instanceField;
    public static void main(String[] args) {
        // a static method can access static fields
        staticField = true;

        // a static method can access instance fields through an object reference
        Example instance = new Example();
        instance.instanceField = true;
    }

[1]:根据运行时特征,它可以是每个ClassLoader或AppDomain或线程一个,但这不是重点。

为了补充现有的答案,让我试着用一张图片:

所有储蓄帐户都适用2%的利率。因此它是静态的。

平衡应该是个体的,所以它不是静态的。

我喜欢在“助手”类中使用静态方法(如果可能的话)。

调用类不需要创建helper类的另一个成员(实例)变量。您只需调用helper类的方法。helper类也得到了改进,因为不再需要构造函数,也不需要成员(实例)变量。

或许还有其他优势。

这个讨论到目前为止忽略了类加载器的注意事项。严格来说,对于给定的类加载器,Java静态字段在类的所有实例之间共享。