
3.7.3 static关键字
创建一个类即描述了其对象的外观和行为。直到使用new关键字时,你才会真正创建一个对象,以及为该对象分配内存,并使得其方法可以被调用。
然而在两种情况下,这种方式会显得不合时宜。第一种情况是,有时候我们需要一小块共享空间来保存某个特定的字段,而并不关心创建多少个对象,甚至有没有创建对象。第二种情况是,你需要使用一个类的某个方法,而该方法和具体的对象无关;换句话说,你希望即便没有生成任何该类的对象,依然可以调用其方法。
static关键字(源自C++)为以上两个问题提供了解决方案。如果你使用了static关键字,则意味着使用static的字段或方法不依赖于任何对象。也就是说,即便你没有为一个类创建任何对象,依然可以调用该类的static方法或static字段。另外,由于非static的字段和方法必须基于指定的对象[6],因此对于非static的字段和方法来说,你必须创建一个对象才可以使用非static的字段或方法。
有些面向对象编程语言也会使用“类数据”(class data)和“类方法”(class method)来表示该数据或方法只服务于类,而非特定的对象。有时候,Java也会使用这两种称谓。
创建一个static字段或方法,只需要把static关键字放置于字段或方法定义的前面就可以了。以下是创建并初始化一个static字段的例子:

即便你创建了两个StaticTest类的对象,StaticTest.i依然只会占用同一块内存空间。也就是说,字段i会被两个对象所共享。例如:

st1.i和st2.i的值都是47,这是因为两者使用的内存空间是相同的。
有两种方法可以调用static变量。其一是通过对象来调用,比如之前例子中的st2.i。此外,你也可以直接通过类名来调用(非static成员则不能这样使用):

这里出现的运算符的作用是将变量的值加1。结果就是,st1.i和st2.i的值都变成了48。
我们较为推荐通过类名调用static变量,因为这种方法突出了变量的static特质。[7]
类似的逻辑也适用于static方法。你既可以通过对象来调用static方法(和非static方法一样),也可以使用专用语法ClassName.method(),即类名加方法名。例如,你可以这样定义一个static方法:

increment()方法通过运算符将static整数i的值加1。你可以使用传统方式,即通过对象调用increment()方法:

不过,推荐的做法是直接通过类名来调用:

将static关键字应用于字段,毫无疑问会改变其数据生成的方式,即static字段是基于类创建的,非static字段则是基于对象创建的。而将static应用于方法时,即便你没有创建对象,也可以调用该方法。你之后会看到,作为运行应用程序的入口,我们在定义main()方法时,static关键字是必不可少的一部分。