前言
最近在阅读 《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
关键字的应用场景
1、静态变量
静态变量属于类,内存中只有一个实例,当类被加载时,就会为该静态变量分配内存空间。存储在 方法区
中,一般情况下不会被回收,除非 JVM
退出。
比如:BigDecimal
类中 1~10
时经常需要使用的,我们开发过程中需要使用 new BigDecimal("10")
创建,BigDecimal
直接提供了静态变量,当类被加载的时候,会初始化到内存中,避免了频繁的创建对象。
2、静态方法
常用于各种 工具类
3、静态代码块
参考 Java - 代码块 这篇文章中的静态代码块部分
参考 Java - 单例模式详解 中的使用静态代码块初始化单例对象
4、静态内部类
参考 Java - 单例模式详解 中的使用静态内部类创建单例对象
5、静态导入
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();
}
在这种情况下,如果不指定具体类名,也会导致代码可读性变差,所以项目中使用不使用,还是要具体情况具体分析。