最近在阅读 《Java编程思想》 这本书,看到 static 关键字这一章节,本以为对于 static 关键字已经很了解了,没想到在又看了一遍之后,还是会有新的理解,特此记录一下。
static ?我们定义了一个类,这个类描述了 一类具有共同特征的对象 的一些 特征 和 行为,比如 鸟类 都有 翅膀、喙,都会 飞,翅膀 就是类的 属性,飞 就是类的 方法,我们只有创建了一个对象,才能使用响应的方法,比如我们创建了一个 麻雀 对象,才能使用 麻雀 的 飞 方法,并可以给 麻雀 的 翅膀 属性赋值,比如 灰色的翅膀。也就是说我们只有创建了类的对象(使用 new 创建对象),才能使用类中定义的 属性 和 方法。
以下两种情形,可以在不 new 对象的时候,使用相应的 属性 和 方法:
为满足以上两种需求,可以使用 static 关键字。一旦将 属性 或 方法 用 static 修饰,那么就不会跟类的任何对象再联系到一起,即使不创建对象也可以调用。
在开发中的应用场景为:常量类 和 工具类。
定义一个 static 修饰的属性:
public class StaticTest {
static int i = 10;
}
现在我们创建两个对象:
StaticTest staticTest1 = new StaticTest();
StaticTest staticTest2 = new StaticTest();
System.out.println(staticTest1.i); // 10
System.out.println(staticTest2.i); // 10
从结果可以看出,两个对象的 i 值是相同的,因为他们引用的是同一片内存区域。
StaticTest.i++;
System.out.println(staticTest1.i); // 11
System.out.println(staticTest2.i); // 11
有两种方法可以引用一个 static 变量,一种是通过对象引用,另一种是使用类名引用,也推荐使用类名引用,可以强调 static 关键字的本质。
StaticTest.i
static 修饰类的属性:
public class Color {
// 静态变量、静态属性
public static String sun = "red";
// 实例变量
public String sea = "bule";
// getter setter
...
}
通过上面的例子,我们知道 static 修饰的属性、方法、代码块、内部类等都是属于类的,非 static 的是属于对象的,只有创建对象的时候才能被调用
也就是说静态的变量是共享的,创建了多个对象,如果静态变量可以被修改(不是 final),那么某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的
public static void main(String[] args) {
Color color = new Color();
Color color2 = new Color();
color.setSea("green");
System.out.println(color2.getSea()); // blue
}
static 关键字的应用场景静态变量属于类,内存中只有一个实例,当类被加载时,就会为该静态变量分配内存空间。存储在 方法区 中,一般情况下不会被回收,除非 JVM 退出。

比如:BigDecimal 类中 1~10 时经常需要使用的,我们开发过程中需要使用 new BigDecimal("10") 创建,BigDecimal 直接提供了静态变量,当类被加载的时候,会初始化到内存中,避免了频繁的创建对象。
常用于各种 工具类
参考 Java - 代码块 这篇文章中的静态代码块部分
参考 Java - 单例模式详解 中的使用静态代码块初始化单例对象
参考 Java - 单例模式详解 中的使用静态内部类创建单例对象
import static com.example.constant.CacheConsts.*;
静态导入是 JDK 1.5 之后新加的功能,比如有一个常量类:CacheConsts:
static 导入的情况下,我们引用其中的常量:public void init() {
CacheConsts.USER_KEY;
CacheConsts.ORDER_KEY;
}
static 导入的情况下,可以省略类名直接引用,简化一部分代码:public void init() {
USER_KEY;
ORDER_KEY;
}
但是在引入工具类的时候,不建议使用这种方式,比如:
public void init() {
isBlank(str);
isNull(str);
getOrderNo();
}
在这种情况下,如果不指定具体类名,也会导致代码可读性变差,所以项目中使用不使用,还是要具体情况具体分析。