main方法都被标记为static修饰符,本文讨论一下该修饰符含义。
一、静态域
若把域定义为static,则每个类中只有一个这样的域。而每一个对象对于所有的实例域都有一份自己的拷贝。例如,给定一个雇员赋予其唯一的标识码,这里给employee添加一个实例域id和 静态域nextId。
class Employee {
private static int nextId = 1;
private int id;
......
}
换句话说,每一个雇员对象都有一个自己的id域,但是这个类的所有实例域将会共享一个nextId域,若有1000个employee对象,则有1000个实例域id,但是只有一个静态域nextId。即使没有雇员对象,静态域nextId也存在。它属于类,不属于任何独立对象。
注释: 在绝大多数面向对象中,静态域称之为类域。static只是沿用了Cpp的叫法,无实际意义。
下面实现了一个简单的方法:
public void setId() {
id = nextId;
nextId++;
}
静态常量
静态变量使用较少,但是静态常量使用较多,如下,Math类定义一个静态常量:
public class Math {
...
public static finale double PI = 3.141592653585;
...
}
前面提到过,由于每个类对象都可以对公共域进行修改,所以不要把域设计为public;另外,共有常量即final域却没有任何问题。
System.out = new PrintStream(....) //Error,out is final
二、静态方法
静态方法是一种不能向对象实施操作的方法。例如Math类的pow方法就是一个静态方法,
Math.pow(x, a);
在运算时,不适用任何Math对象。换句话说,没有隐式的参数。
可以认为静态方法是没有this参数的方法,在一个非静态的方法中,this参数表示这个方法的隐式参数。
employee类的静态方法不可以访问Id实例域,因为它不能操作对象。但是静态方法可以访问自身类中的静态域。下面是一个例子:
public static int getNextId() {
return nextId; //return static field
}
可以通过类名调用这个方法。
int n = Employee.getNextId();
这个方法省略了关键字static吗?答案是确定的,但是需要通过该类对象的引用调用这个方法。
在下面这两种情况下,需要使用静态方法:
- 一个方法不需要访问对象状态,其所需参数都是通过显式参数提供,例如Math.pow。
- 一个方法只需要访问类的静态域。
C++注释:
Java类中的静态域和静态方法与C++相似,但是,在语法树协商稍有不同;C++静态方法
在C++中,使用::操作符访问自身作用域之外的静态域和静态方法,如Math::PI。
起初,C引入static关键字是为了表示退出一个块后依然存在的局部变量,在这种情况下,static是有意义的,变量一直存在,进入块后变量依然存在,随后static在C有了第二个含义,表示不能被其他文件访问的全局变量和函数。
三、工厂方法
静态方法还有另一个常见用途,类似LocalDate和NumberFormat的类使用静态工厂方法来构造对象,
你已经见过工厂方法LocalDate.now和NumberFormat.of,使用工厂方法生成不同风格的格式化对象:
为什么NumberFormat类不利用构造器完成这些操作呢?有如下两个原因:
- 无法命名构造器,构造器的名字必须和类名相同,但是这里希望得到的货币实例和百分比实例采用不同的名字。
- 但是用构造器时候,无法改变所构造的对象类型。而Factory方法会返回一个
decimalFormat对象,这是其子类。