static 关键字主要有两种作用:
第一,为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。
第二,实现某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下就可以通过类来直接调用方法或使用类的属性。
static 主要有 4 种使用情况:成员变量、成员方法、代码块和内部类。
(1) static 成员变量
虽然 java 中没有全局的概念,但可以通过 static 关键字来达到全局的效果。Java提供了两种类型的变量:用 static 关键字修饰的静态变量和不用 static 修饰的实例变量。
静态变量属于类,在内存中只有一个复制(所有实例都指向同一个内存地址),只要静态变量所在的类被加载,这个静态变量就会被分配空间,因此就可以被使用了。
对静态变量的引用有两种方式:
类.静态变量
对象.静态变量
实例变量属于对象,只有对象被创建后,实例变量才会被分配空间,才能被使用。它在内存中有多个复制。
只能用 对象.实例变量 来引用。
以下是静态变量和实例变量的使用示例。
public class Test {
private static int staticInt = 0;
private int nonStaticInt = 0;
public static void main(String[] args) {
Test t = new Test();
System.out.println("t.staticInt = " + t.staticInt);
System.out.println("Test.staticInt = " + Test.staticInt);
System.out.println("t.nonStaticInt = " + t.nonStaticInt);
System.out.println("对静态变量和实例变量分别 + 1 后:");
t.staticInt++;
t.nonStaticInt++;
Test t1 = new Test();
System.out.println("t1.staticInt = " + t1.staticInt);
System.out.println("Test.staticInt = " + Test.staticInt);
System.out.println("t1.nonStaticInt = " + t1.nonStaticInt);
}
}/* Output:
t.staticInt = 0
Test.staticInt = 0
t.nonStaticInt = 0
对静态变量和实例变量分别 + 1 后:
t1.staticInt = 1
Test.staticInt = 1
t1.nonStaticInt = 0
*///~
上例说明,静态变量只有一个,被类拥有,所有对象都共享这个静态变量,而实例对象是与具体对象相关的。
(2) static 方法
static 方法是类的方法,不需要创建对象就可以被调用,而非 static 方法是对象的方法,只有对象被创建出来后才可以使用。
static 方法中不能使用 this 和 super 关键字,
不能访问非static类型的变量,
不能调用非 static 方法,
只能访问所属类的静态成员变量和成员方法。因为当 static 方法被调用时,这个类的对象可能还没被创建,即使已经被创建了,也无法确定调用哪个对象的方法。
static 的一个很重要的用途是实现单例模式。
单例模式的特点是该类只有一个实例,为了实现这一功能,必须隐藏类的构造函数,即把构造函数声明为 private,并提供一个创建对象的方法,该方法被声明为 static。示例如下:
class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
用 public 修饰的 static 变量和方法本质上都是全局的。若在 static 变量前用 private 修饰,则表示这个变量可以在类的静态代码块或类的其他静态成员方法中使用,但不能在其他类中通过类名来直接引用。
(3) static 代码块
static 代码块在类中是独立于成员变量和成员方法的代码块的。它不在任何一个方法体内,JVM 在加载类时会执行 static 代码块,如果有多个,则按顺序执行。static 代码块经常被用来初始化静态变量。注意,静态代码块只会被执行一次。
public class Test {
private static int a;
static {
Test.a = 5;
System.out.println(a);
System.out.println("static block is called");
}
public static void main(String[] args) {}
}/* Output:
4
static block is called
*///~
(4) static 内部类
static 内部类是指被声明为 static 的内部类,它可以不依赖于外部类实例对象而被实例化。
静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类中的静态成员变量和静态方法(包括私有的)。
public class Outer {
static int n = 5;
static class Inner {
void f() {
System.out.println("Inner:Outer.n = " + n);
}
}
public static void main(String[] args) {
Outer.Inner oi = new Outer.Inner();
oi.f();
}
}/* Output:
Inner:Outer.n = 5
*///~
需要注意的是,只有内部类才能被定义为 static。