static关键字
由static关键字修饰的成员称为静态成员,该关键字可以用来修饰:
- 变量
- 方法
- 代码块
- 内部类
静态成员属于它所在的类,不同于类的实例成员,每一个对象实例都有一份自己的拷贝,静态成员在类中只有一份,被所有对象实例共享。
同时,静态成员的存储位置也不同,静态成员存储在方法区,实例成员则存储在栈中。
静态变量
定义一个类,类中包含一个静态变量和一个实例变量
class A {
private static int i;
private int j;
public static setI(int i) {
A.i = i;
}
public static getI() {
return i;
}
public setJ(int j) {
this.j = j;
}
public getJ() {
return j;
}
}
对于A类来说,每一个对象都有一个自己的j
,但这个类的所有实例共享一个i
。静态变量的初始化是在类的初始化过程中完成的,也就是说即使A类没有创建人和一个实例对象,i
也存在。
举例说明一下:
public class StaticTest {
public static main(String[] args) {
A a1 = new A();
A a2 = new A();
a1.setI(1);
a2.setI(2);
a1.setJ(3)
a2.setJ(4);
System.out.println("a1.i = " + a1.getI());
System.out.println("a2.i = " + a2.getI());
System.out.println("a1.j = " + a1.getJ());
System.out.println("a2.j = " + a2.getI());
}
}
结果为:
a1.i = 2
a2.i = 2
a1.j = 3
a2.j = 4
其中,通过a1和a2均对i赋值,发现a1赋的值被a2所覆盖,可以得到a1实例与a2实例共享一份静态变量i。
静态变量可以通过类直接调用,也可以通过对象实例调用,但是一般不推荐。
当一个成员变量为静态的,其getter/setter方法也必须为静态的。
静态常量
静态常量是更加常见的使用方式,用static
和final
两个关键字修饰,可以直接使用类调用。
常用的静态常量有Math.PI
,System.out
等等
与静态成员变量不同的是,静态常量常常被声明为public,这是因为常量被声明为final,所以它的值不允许修改。
静态方法
静态方法是一种不能操作对象的方法,在静态方法中不能访问非静态的变量,同时也不能通过this
来读取变量和调用方法。
类的对象可以调用静态方法,但是不推荐使用,因为静态方法返回的结果与对象本身并无关系。
有两种情况需要使用静态方法:
- 一个方法不需要访问对象状态,其所需参数都是现实提供的,例如:
Math.abs
- 一个方法只需要访问类的静态域,例如:
A.getI()
工厂方法
工厂方法是静态方法的一个常见用途,类可以通过静态的工厂方法创建对象,例如LocalDate.now()
就是创建一个当前时间的LocalDate
对象。
NumberFormat
类也是用工厂方法来生成不同格式的格式化对象,例如:
NumberFormat currency = NumberFormat.getCurrencyInstance();
NumberFormat percent = NumberFormat.getPercentInstance();
double d = 0.1;
System.out.println(currency.format(d));
System.out.println(percent.format(d));
/*
* 结果
* $0.10
* 10%
*/
工厂方法可以使用户只关心对应类的工厂,而不用关心类的具体实现,提高了系统的扩展性。
静态内部类
用static
关键字修饰的内部类称之为静态内部类。
静态内部类的创建不需要外部类的对象,直接通过new Outer.Inner()
方式调用构造方法即可。
静态内部类的方法可以访问外部类的静态成员,不可以访问非静态成员。
静态内部类也有自己的字节码文件,文件名为Outer$Inner.class